perl – 为什么括号只在子声明后可选?

前端之家收集整理的这篇文章主要介绍了perl – 为什么括号只在子声明后可选?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
(假设使用严格;使用警告;整个这个问题。)

我正在探索sub的用法

sub bb { print @_; }
bb 'a';

这按预期工作。括号是可选的,与许多其他函数一样,如打印,打开等。

但是,这会导致编译错误

bb 'a';
sub bb { print @_; }

String found where operator expected at t13.pl line 4,near "bb 'a'"
        (Do you need to predeclare bb?)
@R_301_156@ error at t13.pl line 4,near "bb 'a'"
Execution of t13.pl aborted due to compilation errors.

但这不:

bb('a');
sub bb { print @_; }

同样,一个没有args的子例如:

special_print;
my special_print { print $some_stuff }

将导致此错误

Bareword "special_print" not allowed while "strict subs" in use at t13.pl line 6.
Execution of t13.pl aborted due to compilation errors.

缓解这一特定错误方法是:

>放置&在子名称之前,例如。 & special_print
>将空括号放在子名称后面,例如。 special_print()
> Predeclare special_print with sub special_print在脚本的顶部。
>在子声明之后调用special_print。

我的问题是,为什么这种特殊治疗?如果我可以在脚本中全局使用一个sub,为什么我不能使用它任何方式我想要它?有没有一个逻辑,sub子实现这种方式?

ETA:我知道我该如何解决它。我想知道这背后的逻辑。

解决方法

我想你缺少的是,Perl使用严格的一遍解析器。它不扫描文件的子程序,然后回去编译其余的。知道这一点,下面描述一次通过解析系统如何工作:

在Perl中,用于声明子例程的子NAME语法等效于以下内容

sub name {...}   ===   BEGIN {*name = sub {...}}

这意味着子NAME语法具有编译时效果。当Perl解析源代码时,它使用当前的一组声明。默认情况下,集合是内置函数。由于Perl已经知道这些,它允许你省略括号。

一旦编译器命中一个BEGIN块,它就使用当前规则集编译块的内部,然后立即执行该块。如果该块中的任何内容更改规则集(例如向当前命名空间添加子例程),那么这些新规则将对解析的其余部分有效。

没有预先声明的规则,标识符将被解释如下:

bareword       ===   'bareword'   # a string
bareword LIST  ===   @R_301_156@ error,missing ','
bareword()     ===   &bareword()  # runtime execution of &bareword
&bareword      ===   &bareword    # same
&bareword()    ===   &bareword()  # same

当使用严格和警告,如你所说,barewords不会转换成字符串,所以第一个例子是语法错误

当用以下任何一种预先声明:

sub bareword;
use subs 'bareword';
sub bareword {...}
BEGIN {*bareword = sub {...}}

然后标识符将被解释如下:

bareword      ===   &bareword()     # compile time binding to &bareword
bareword LIST ===   &bareword(LIST) # same
bareword()    ===   &bareword()     # same
&bareword     ===   &bareword       # same
&bareword()   ===   &bareword()     # same

因此,为了使第一个示例不是语法错误,必须首先查看先前的子例程声明之一。

至于为什么在这一切后面,Perl有很多遗产。开发Perl的目标之一是完全向后兼容。在Perl 1中工作的脚本仍然在Perl 5中工作。因此,不可能更改围绕裸词解析的规则。

也就是说,你会很难找到一种更灵活的语言,让你调用子程序。这允许您找到最适合您的方法。在我自己的代码中,如果我需要在声明之前调用一个子程序,我通常使用name(…),但是如果该子程序有一个原型,我将它称为& name(…)你会得到一个警告“子程序调用太早检查原型”,如果你不这样调用)。

猜你在找的Perl相关文章