在 Perl 中,函数调用已优化为始终不需要 & 印记。当你声明一个子程序时:
sub hello {print "world\n"}
您可以将其称为hello; 或hello(); 或&hello();,它们都会做同样的事情。
如果你的子程序接受参数,那就有点不同了:
sub hello {print "Hello, @_!\n"}
hello 'World'; # prints 'Hello, World!'
hello('World'); # same
&hello('World'); # same
hello; # prints 'Hello, !'
&hello(); # same
&hello; # different, uses whatever was in @_ when hello was called
@_ = 'Bob';
hello; # prints 'Hello, !'
&hello(); # prints 'Hello, !'
&hello; # prints 'Hello, Bob!'
如您所见,使用& 印记在很大程度上是多余的,除非在没有参数列表的情况下。在这种情况下,使用@_ 中的当前值调用子例程。
& 印记还有另一个特殊行为,与 Perl 的原型有关。假设您正在编写自己的 keys 函数,并希望它的行为类似于 Perl:
sub mykeys (\%) {keys %{$_[0]}}
这里的(\%) 原型告诉perl mykeys 的第一个参数必须是文字哈希(将作为哈希引用传入)。
my $hashref = {...};
say for mykeys %$hashref;
如果由于某种原因您需要绕过这个要求(通常不是最好的主意),您可以这样写:
say for &mykeys( $hashref ); # note that there is no `%`
在这种情况下,在 sub 之前添加 & 会禁用原型检查以及它会执行的任何后续操作(例如获取引用)。在这种用法中,& 基本上是一个断言,即您确切知道 mykeys 需要什么参数,并且您不希望 perl 妨碍您。
一般而言,应避免在子例程上使用&,除非您明确想要我上面提到的行为之一。
最后,& 在参考实际代码参考时也是需要的:
my $coderef = \&hello;
或
if (defined &hello) {print "hello is defined\n"} # but is not called
正如其他人所提到的,my 运算符在当前词法范围内声明变量。加载 use strict; pragma 时需要它。 Perl 有两种类型的变量,用my 声明的词法变量和包变量。
my 变量存在于所谓的词法填充中,这是 Perl 每次引入新作用域时创建的存储空间。包变量存在于全局符号表中。
use strict;
use warnings;
$main::foo = 5; # package variable
{ # scope start
my $foo = 6;
print "$foo, $main::foo\n"; # prints '6, 5';
} # scope end
print "$foo, $main::foo\n"; # syntax error, variable $foo is not declared
您可以使用our 关键字为全局变量创建词法别名:
use strict;
our $foo = 5; # $main::foo == $foo
{ # scope start
my $foo = 6;
print "$foo, $main::foo\n"; # prints '6, 5';
} # scope end
print "$foo, $main::foo\n"; # prints '5, 5'
# since $foo and $main::foo are the same