开发者

Why does Perl evaluate code in ${...} during string interpolation?

开发者 https://www.devze.com 2022-12-21 09:25 出处:网络
Why does the following snippet work at all? And what evil might be possible us开发者_C百科ing this? But seriously, is there any reason, the code in ${} gets evaluated at all and then used as scalar re

Why does the following snippet work at all? And what evil might be possible us开发者_C百科ing this? But seriously, is there any reason, the code in ${} gets evaluated at all and then used as scalar reference?

use strict;
no strict 'refs';

our $message = "Hello world!";
print "${ lc 'MESSAGE' }\n";


We explain this in depth in Intermediate Perl.

The general syntax for variable lookups is:

 SIGIL  BLOCK  INDEXY-THING

For a simple scalar that looks like:

 print $   { foo };

You have probably seen this when you need to separate a variable name from things surrounding it:

 print "abc${foo}def\n";

If you just have a Perl identifier in the block and no surrounding mess, you can leave off the braces, which is the common case:

 print $foo;

However, this is the same thing for dereferencing a reference:

 SIGIL  BLOCK-RETURNING-REFERENCE  INDEXY-THINGS

If the thing that you get in the block is a reference, Perl tries to dereference it like you asked it too:

 my $ref = \ '12345';
 print $     { $ref };

That's a real block though, and not just sugar. You can have as many statements as you like in there:

 print $     { my $ref = \ '1234'; $ref };

Now you're not just specifying a Perl identifier, so Perl doesn't assume that you're giving it an identifier and it executes code and uses the result as a reference. Consider the difference between these almost identical say statements:

    use 5.010;
our $foo = "I'm the scalar";

sub foo { \ "I'm the sub" }

say ${foo};
say ${foo;};

In that second say Perl sees the semi-colon, realizes it's not an identifier, interprets the code inside the braces as text, and returns the result. Since the result is a reference, it uses the ${...} to dereference it. It doesn't matter where you do this, so that you do it inside a double-quoted string is not special.

Also, notice the our there. That's important now that you're going to consider something a bit more tricky:

    use 5.010;
our $foo = "I'm the scalar";

sub foo { \ "I'm the sub" }
sub baz { 'foo' }

say ${foo};
say ${foo;};
say ${baz;};

Perl intreprets that last say as code and sees the result is not a reference; it's the simple string foo. Perl sees that it's not a reference but it's now in a dereferencing context so it does a symbolic reference (as Greg Bacon describes). Since symbolic references work with variables in the symbol table, that $foo had to be a package variable.

Since it's easy to mess this up, strict has a handy check for it. However, when you turn it off, don't be surprised when it bites you. :)


From the "Using References" section of the perlref documentation:

Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type. In other words, the previous examples could be written like this:

$bar = ${$scalarref};
push(@{$arrayref}, $filename);
${$arrayref}[0] = "January";
${$hashref}{"KEY"} = "VALUE";
&{$coderef}(1,2,3);
$globref->print("output\n");  # iff IO::Handle is loaded

Admittedly, it's a little silly to use the curlies in this case, but the BLOCK can contain any arbitrary expression, in particular, subscripted expressions:

&{ $dispatch{$index} }(1,2,3);    # call correct routine

Because of being able to omit the curlies for the simple case of $$x, people often make the mistake of viewing the dereferencing symbols as proper operators, and wonder about their precedence. If they were, though, you could use parentheses instead of braces. That's not the case. Consider the difference below; case 0 is a short-hand version of case 1, not case 2:

$$hashref{"KEY"}   = "VALUE";     # CASE 0
${$hashref}{"KEY"} = "VALUE";     # CASE 1
${$hashref{"KEY"}} = "VALUE";     # CASE 2
${$hashref->{"KEY"}} = "VALUE";   # CASE 3

Case 2 is also deceptive in that you're accessing a variable called %hashref, not dereferencing through $hashref to the hash it's presumably referencing. That would be case 3.

Later in "Symbolic references":

We said that references spring into existence as necessary if they are undefined, but we didn't say what happens if a value used as a reference is already defined, but isn't a hard reference. If you use it as a reference, it'll be treated as a symbolic reference. That is, the value of the scalar is taken to be the name of a variable, rather than a direct link to a (possibly) anonymous value.


It's ok, unless you use symbolic references. Suppose the following code:

my %messages = (hello => "Hello world!", bye => "Bye-bye, world!");
sub get_message_ref { return \$messages{$_[0]} }; # returns scalarref
print "${ get_message_ref('bye') }\n";

Agree, its usefulness is not obvious with scalarrefs, but it is very useful with arrayrefs.

print "keys: @{[keys %messages]}\n";
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号