【问题标题】:Perl `defined' and `undef' subroutine scopePerl `defined' 和 `undef' 子例程范围
【发布时间】:2017-01-28 06:23:33
【问题描述】:

请看下面的代码:

use strict;
use warnings;


print "subroutine is defined\n" if defined &myf;
myf();

sub myf
{
        print "called myf\n";
}

undef &myf;
#myf();
print "now subroutine is defined\n" if defined &myf;

输出是

subroutine is defined
called myf

第一个print 语句可以打印,这是否意味着解释器(或编译器?)进一步查看并看到子程序定义?如果是这样,为什么它没有将undef &myf; 视为第二个print 语句?

谢谢

【问题讨论】:

  • 因为undef 是在运行时运行的代码,而sub 是一个定义并且发生在编译时。

标签: perl subroutine defined undef


【解决方案1】:

这与作用域无关,而与编译时间运行时间有关。这是一个简化的解释。

Perl 解释器最初会扫描您的代码,并遵循任何use 语句或BEGIN 块。此时,它会看到所有subs,并将它们记录在各自的包中。所以现在你的符号表中有一个&::myf

当编译时间到达程序的末尾时,它将切换到运行时间。

此时,它实际上运行了代码。如果定义了&myf,则执行您的第一个print 语句。我们知道它是,因为它是在编译时设置的。 Perl 然后调用该函数。一切都很好。现在你 undef 符号表中的那个条目。这也发生在运行时。

之后,defined &myf 返回 false,因此不会打印。

你甚至在代码中有第二次调用myf(),但被注释掉了。如果你删除评论,它会抱怨Undefined subroutine &main::myf called。这很好地暗示了发生的事情。

所以实际上它在代码中并没有向前或向后看。那个时候已经扫完码了。


不同阶段解释in perlmod

请注意,实际上undef 函数的用例并不多。我不明白你为什么要删除它,除非你想手动清理你的命名空间。

【讨论】:

  • 很好的答案,但它没有解释为什么我不能在定义子例程之前写一个语句myf;(甚至main::myf;)。
  • @Borodin: 因为在编译时编译器不知道myfmain::myf 裸字是子程序(关闭use strict 你会得到:Bareword "myf" not allowed while "strict subs" in use。在定义子程序后你在你的符号表中有一个&::myf,你可以在定义后写裸字myfmain::myf。为了确保你想调用子程序,只需在裸字后面加上括号:myf()
  • 这不是问题的一部分@Borodin ;)
  • @simbabque:不,不是。但从表面上看,它似乎与编译填充符号表以便子例程在运行时可用的想法相矛盾。丑陋的事实是编译器假定一个简单的myf 实际上是一个字符串,尽管use strict 'subs' 已经到位,并且尽管它在被视为字符串时会产生警告Useless use of a constant ("myf") in void context。一切都是为了向后兼容!
  • @Borodin 前几天我读到了这个。可能是另一个问题。有人可能会讨论最终删除它吗?
猜你喜欢
  • 1970-01-01
  • 2011-05-03
  • 2021-02-18
  • 2021-02-17
  • 2014-10-06
  • 2012-08-09
  • 2015-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多