为什么下面的代码片段能起作用?使用这个可能会带来什么邪恶呢?但说真的,有什么原因吗,代码中 ${} 完全被评估然后用作标量参考?

use strict;
no strict 'refs';

our $message = "Hello world!";
print "${ lc 'MESSAGE' }\n";
有帮助吗?

解决方案

没关系, 除非你使用符号引用. 。假设有以下代码:

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

同意,它的用处对于 scalarrefs 来说并不明显,但是对于 arrayrefs 来说非常有用。

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

其他提示

我们深入解释了这一点 中级 Perl.

变量查找的一般语法是:

 SIGIL  BLOCK  INDEXY-THING

对于一个简单的标量,如下所示:

 print $   { foo };

当您需要将变量名称与其周围的内容分开时,您可能已经看到过这一点:

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

如果块中只有一个 Perl 标识符并且周围没有混乱,则可以省略大括号,这是常见的情况:

 print $foo;

然而,这与取消引用引用是一样的:

 SIGIL  BLOCK-RETURNING-REFERENCE  INDEXY-THINGS

如果你在块中得到的东西是一个引用,Perl 会尝试像你要求的那样取消引用它:

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

但这是真正的块,而不仅仅是糖。您可以在其中添加任意数量的语句:

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

现在您不只是指定 Perl 标识符,因此 Perl 不会假设您给它一个标识符,它会执行代码并使用结果作为引用。考虑一下这些几乎相同的之间的差异 say 声明:

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

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

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

在那一秒 say Perl 看到分号,意识到它不是标识符,将大括号内的代码解释为文本,并返回结果。由于结果是参考,因此它使用 ${...} 取消引用它。在哪里执行此操作并不重要,因此在双引号字符串内执行此操作并不特殊。

另外,请注意 our 那里。这一点很重要,因为你要考虑一些更棘手的事情:

    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 解释了最后一个 say 作为代码,看到的结果不是参考;这是简单的字符串 foo. 。Perl 发现它不是一个引用,但它现在处于解引用上下文中,因此它执行符号引用(如 格雷格·培根描述)。由于符号引用使用符号表中的变量,因此 $foo 必须是一个包变量。

因为很容易搞砸 strict 有一个方便的检查。然而,当你把它关掉时,当它咬你时不要感到惊讶。:)

“使用参考” 的perlref文档的部分:

  

任何你就会把一个标识符(或标识符的链)作为变量或子程序名称的一部分,则可以替换为BLOCK返回正确的类型的参考标识符。换句话说,前面的实施例可以写成如下:

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

诚然,这是一个有点傻使用花括号在这种情况下,但块可以包含任意的表达,特别是,下标表达式:

&{ $dispatch{$index} }(1,2,3);    # call correct routine
     由于能够省略花括号为$$x的简单情况的

,人们往往使观看解引用符号正确的运营商对他们的优先级的错误,和奇迹。如果他们成功了,但是,你可以使用括号,而不是括号。这是不是这样的。考虑下面的差异;情况下为0是壳体1的短手版,不区分2:

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

案例2处还在于你所访问的变量称为%hashref,通过$hashref不取消引用到它的大概引用哈希欺骗性。这将是壳体3。

后来在 “符号引用”:

  

我们说,引用弹入存在的必要,如果他们是不确定的,但我们并没有说,如果作为一个参考值已定义发生了什么,但不是硬引用。如果你使用它作为一个参考,它会被当作一个符号引用。也就是说,标量的值被取为变量的名称,而不是直接连接到一个(可能)匿名值。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top