我正在探索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中,用于声明子例程的子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(…)你会得到一个警告“子程序调用太早检查原型”,如果你不这样调用)。