【问题标题】:Perl syntax sigilPerl 语法标志
【发布时间】:2011-06-28 23:37:04
【问题描述】:

请问&在subs前面有什么用,没有它,subs仍然可以运行。

还有,perl 变量前面的my

我知道这是为了严格的语言语法或其他什么,但他们为什么不把它作为一个标准,每个变量都需要由 my 声明?

编辑

感谢您的所有讨论/回答,我希望接受您的许多回答,但由于我只能接受一个,我将接受其他用户可能容易理解的一个。

【问题讨论】:

  • 对于未来的读者:Eric Strom 的答案是唯一一个完全正确的答案。 & 的原型失败行为很重要。

标签: perl syntax


【解决方案1】:

在 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

【讨论】:

  • 感谢您非常全面的回答和解释
  • @Eric Strom:你说 & 通常不应该使用。但是,我注意到如果您使用 &sub 进行子例程调用,emacs 会很好地突出显示语法。将它们用于此目的是否有特定的缺点或危险?或者,最好是,有没有办法让 emacs 在没有它的情况下语法高亮 subs?
  • @YGomez => 一直使用& 的危险在于&mysub&mysub() 做了非常不同的事情(前者调用当前值为@_ 的子,后者使用空参数列表调用 sub)。由于这两个名称在视觉上非常相似,因此很容易将一个误认为另一个,这将导致难以诊断错误。由于 Perl 在大多数地方都不需要 &,因此最好将其排除在外,仅在您明确需要它可以提供的行为时使用它。就 emacs 而言,我相信还有其他语法高亮模式。
  • 还值得注意的是&foo;foo(@_); 在执行上是不同的——前者更像是一个goto,将堆栈留在原地,在极少数和非常特殊的情况下,如深尾递归,可以带来巨大的性能胜利。
【解决方案2】:

my 将变量限制在当前范围内。使用您应该使用的use strict pragma,您必须声明变量(例如使用my)。出于灵活性的原因,对于非常短的脚本,存在可以不用的替代方案。

& 很少再使用,因为 Perl 默认将无印记的词解释为子例程,但如果您想创建对子例程的引用,它很有用。

sub say_hi { print "hi\n" }
my $sub_ref = \&say_hi;

【讨论】:

  • 简单直接的答案.. 感谢您的澄清 =)
【解决方案3】:

请问subs前面的&有什么用,没有它,subs仍然可以运行。

向后兼容 Perl 4

还有,perl 变量前面的 my。

它设置块范围

我知道这是为了严格的语言语法或其他什么,但他们为什么不把它作为一个标准,每个变量都需要由 my 声明?

  1. 向后兼容性(因此use strict; 不允许裸变量声明)
  2. 变量也可以用ourlocal声明

【讨论】:

  • 另外,用perl -e 不用my 写1 行更容易。
【解决方案4】:

如果你想知道如何编写现代 Perl,我可以推荐你阅读Modern Perl 吗? 您可以购买死树版或免费下载电子版。

【讨论】:

  • 看起来不错。我会试一试。这个问题更让我烦恼,因为我看到许多不同的网站具有不同的实现。没有阅读他们的发布日期可能是我自己的错。
【解决方案5】:

& 仍然有很好的区别:用它调用 (&YourSub) 使当前的@_ 对被调用的 sub 也可见。无论如何,我在我的脚本中使用它主要是为了清楚起见:它明确了哪些是我自己的函数,哪些函数来自核心或模块。

关于my。每个教程和文档都建议使用use strict; pragma,因此您也可以使用my 声明您的变量。所以,从我的角度来看,情况是相当倒退的:如果范围对于最佳实践如此重要,那么默认情况下变量是范围是正常的(就像我们现在用my 说的那样)并且当我们真的需要全局变量时,我们应该这样声明它们。我知道这是 perl 的遗产,但仍然违反 Perl 的意识形态来避免冗余。每次使用my 进行声明可能会被某种编译指示覆盖。 [抱歉,robobooga,可能离你的问题太远了]

【讨论】:

  • 不幸的是,如果 Perl 5.14 默认启用 strict,那么所有现有的 use strict 的 Perl 代码都会立即损坏。 Perl 5.12 在这个方向上走了一点路:如果你 use 5.012,那么 strict 会自动启用。
  • @mscha: 是的,我明白,没有办法为每个写在那里的脚本默认设置 strict-pragma,但我梦想着 pragma,所有变量在其范围内默认是本地的,并且当我需要全局变量时,我使用our 明确声明它们
  • 我其实不介意经常使用my。当我在最外层范围内有一个变量并且还声明了一个具有相同名称的变量的函数时(为了清楚起见,以自己的方式)我知道我在 sub 中获得了一个新变量,因为现在我必须不考虑使用我的而不是思考使用它。
猜你喜欢
  • 2018-01-11
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 2014-11-25
  • 2015-09-09
  • 2020-09-21
  • 2018-12-14
  • 1970-01-01
相关资源
最近更新 更多