如果我有如下所示的代码块:
{
say $myVar;
my $myVar=1;
}
Run Code Online (Sandbox Code Playgroud)
我得到预期的错误:
Variable '$myVar' is not declared
Run Code Online (Sandbox Code Playgroud)
但是,以类似的方式 sub
{
test();
my sub test() {
say "Hello";
}
}
Run Code Online (Sandbox Code Playgroud)
这运行没有错误并打印:
Hello
Run Code Online (Sandbox Code Playgroud)
两者$myVar
和test
在封闭块之外都不可见,因此从某种意义上来说,它们都在词法范围内。
的sub
必须具有其声明“悬挂”于块的顶部,test
在其中的代码位置之前定义的和可用的。但是,我找不到参考资料来支持这一点。
引发此问题的原因是查看my subs
perl 中的词法作用域,这在上面第二种情况的perl版本中给出了“未定义的子例程”错误。以我对词汇范围的理解,这就是我所期望的。
我不加思索地使用它...编写一些测试代码,然后将其包装到sub
文件底部的声明中,并从文件的较早部分调用子程序。一切正常!
它确实导致了一个问题:在这种意义上,perl6 subs真的在词法范围内吗?
当Perl6遇到函数调用时,它将对其进行记录,但不会检查该函数是否存在。
因此,以下内容可以编译,但实际上不起作用。(该函数在调用它的位置不可用。)
foo 1;
my &foo = &say;
Run Code Online (Sandbox Code Playgroud)
下面,编译器执行相同的操作,但是优化器意识到,它甚至无法在任何地方找到对该函数的引用。(因此,优化器会导致其在编译期间失败。)
bar 1;
Run Code Online (Sandbox Code Playgroud)
与其他变量之间存在差异的原因是,很多时候您可能有一个函数依赖于另一个函数,或者您想将这些函数放在其余的代码之后。
同样,函数的代码通常在编译时就知道了,而变量的值直到赋值后才知道。(分配在运行时发生。)
基本上,人们倾向于使用变量和函数的方式是不同的,因此它们的工作方式略有不同。
无需要求在使用它们之前先声明它们,从而消除了限制。
在Perl5中,函数会根据其原型修改解析器,因此编译器需要先查看一个声明,然后才能使用该声明来知道应如何解析它们。
use v5.10;
sub foo ();
sub bar;
say foo + 1; # foo() + 1 # foo is compiled as a term/constant
say bar + 1; # bar( +1 )
sub foo () { 2 }
sub bar { $_[0] + 2 }
Run Code Online (Sandbox Code Playgroud)
在Perl6中,所有函数都像列表一样进行编译,因此无需要求将它们预先声明。
use v6;
# these two lines don't really change anything.
sub foo () {...}
sub bar ($) {...}
say foo + 1; # foo( +1 ) # optimization failure (too many arguments)
say bar + 1; # bar( +1 )
sub foo () { 2 }
sub bar ( $a ) { $a + 2 }
Run Code Online (Sandbox Code Playgroud)