Perl 子程序没有词法作用域是一个设计缺陷吗?
{
sub a {
print 1;
}
}
a;
一个错误,是吗?
a
不应该从外部获得。
它在 Perl 6* 中工作吗?
* 抱歉我还没有安装。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
{
sub a {
print 1;
}
}
a;
一个错误,是吗?
a
不应该从外部获得。
它在 Perl 6* 中工作吗?
* 抱歉我还没有安装。
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(7)
你是在问为什么潜艇在区块之外可见吗?如果是这样,那么它是因为编译时
sub
关键字将 sub 放在main
命名空间中(除非您使用package
关键字创建新的命名空间)。您可以尝试类似的方法在这种情况下,
sub
关键字不是创建子并将其放入main
命名空间中,而是创建一个匿名子例程并将其存储在词法中作用域变量。当变量超出范围时,它不再可用(通常)。要了解更多信息,请查看
perldoc perlsub
另外,您知道吗你可以检查 Perl 解析器如何看待你的代码吗?使用标志
-MO=Deparse
运行 perl,如perl -MO=Deparse yourscript.pl
中所示。您的原始代码解析为:首先编译子程序,然后运行一个没有代码的块,然后调用
a
。对于我在 Perl 6 中的示例,请参阅:成功、失败。请注意,在 Perl 6 中,取消引用是
.
而不是->
。编辑:我添加了另一个答案,关于 Perl 5.18 预期的词法子例程的新实验支持。
Are you asking why the sub is visible outside the block? If so then its because the compile time
sub
keyword puts the sub in themain
namespace (unless you use thepackage
keyword to create a new namespace). You can try something likeIn this case the
sub
keyword is not creating a sub and putting it in themain
namespace, but instead creating an anonymous subroutine and storing it in the lexically scoped variable. When the variable goes out of scope, it is no longer available (usually).To read more check out
perldoc perlsub
Also, did you know that you can inspect the way the Perl parser sees your code? Run perl with the flag
-MO=Deparse
as inperl -MO=Deparse yourscript.pl
. Your original code parses as:The sub is compiled first, then a block is run with no code in it, then
a
is called.For my example in Perl 6 see: Success, Failure. Note that in Perl 6, dereference is
.
not->
.Edit: I have added another answer about new experimental support for lexical subroutines expected for Perl 5.18.
在 Perl 6 中,sub 确实是词法作用域的,这就是代码抛出错误的原因(正如一些人已经指出的那样)。
这有几个有趣的含义:
In Perl 6, subs are indeed lexically scoped, which is why the code throws an error (as several people have pointed out already).
This has several interesting implications:
子例程是包作用域的,而不是块作用域的。
Subroutines are package scoped, not block scoped.
Perl 中的命名子例程被创建为全局名称。其他答案已经展示了如何通过将匿名子分配给词法变量来创建词法子例程。另一种选择是使用
本地
变量来创建动态范围的子变量。两者之间的主要区别在于调用方式和可见性。动态范围的子程序可以像命名子程序一样被调用,并且它也将是全局可见的,直到它定义的块离开为止。
这应该打印
Named subroutines in Perl are created as global names. Other answers have shown how to create a lexical subroutines by assigning an anonymous sub to a lexical variable. Another option is to use a
local
variable to create a dynamically scoped sub.The primary differences between the two are call style and visibility. The dynamically scoped sub can be called like a named sub, and it will also be globally visible until the block it is defined in is left.
This should print
冒着再次受到 @tchrist 责骂的风险,为了完整性,我添加了另一个答案。尚未发布的 Perl 5.18 预计将包含词法子例程作为实验性功能。
这里是相关文档的链接。 再说一遍,这是非常实验性的,它不应该用于生产代码,原因有两个:
所以如果你愿意的话可以玩这个新玩具,但你已经被警告了!
At the risk of another scolding by @tchrist, I am adding another answer for completeness. The as yet to be released Perl 5.18 is expected to include lexical subroutines as an experimental feature.
Here is a link to the relevant documentation. Again, this is very experimental, it should not be used for production code for two reasons:
So play with this new toy if you want, but you have been warned!
如果您看到代码编译、运行并打印“1”,那么您没有遇到错误。
您似乎期望子例程只能在定义它们的词法范围内调用。这将很糟糕,因为这意味着将无法调用其他文件中定义的子例程。也许您没有意识到每个文件都是在其自己的词法范围内评估的?这使得像
If you see the code compile, run and print "1", then you are not experiencing a bug.
You seem to be expecting subroutines to only be callable inside the lexical scope in which they are defined. That would be bad, because that would mean that one wouldn't be able to call subroutines defined in other files. Maybe you didn't realise that each file is evaluated in its own lexical scope? That allows the likes of
是的,我认为这是一个设计缺陷 - 更具体地说,最初选择使用动态作用域而不是 Perl 中的词法作用域,这自然会导致这种行为。但并非所有语言设计者和用户都会同意。所以你问的问题没有明确的答案。
Perl 5 中添加了词法作用域,但作为可选功能,您始终需要专门指出它。对于这种设计选择,我完全同意:向后兼容性很重要。
Yes, I think it is a design flaw - more specifically, the initial choice of using dynamic scoping rather than lexical scoping made in Perl, which naturally leads to this behavior. But not all language designers and users would agree. So the question you ask doesn't have a clear answer.
Lexical scoping was added in Perl 5, but as an optional feature, you always need to indicate it specifically. With that design choice I fully agree: backward compatibility is important.