我需要在运行时从 Perl 符号表中删除一个方法。我尝试使用 来执行此操作undef &Square::area
,它确实删除了该功能,但留下了一些痕迹。具体来说,当$square->area()
被调用时,Perl 抱怨它是“不是代码引用”而不是“未定义的子例程 &Square::area called”,这是我所期望的。
你可能会问,“为什么重要?你删除了这个函数,你为什么要调用它?” 答案是我不叫它,Perl 是。Square 继承自 Rectangle,我希望继承链传递$square->area
到&Rectangle::area
,但不是跳过该方法不存在的 Square 然后落入 Rectangle 的 area(),而是方法调用以“不是 CODE 引用”而终止。
奇怪的是,这似乎只发生在 &Square::area 由 typeglob 赋值定义时(例如*area = sub {...}
)。如果函数是使用标准sub area {}
方法定义的,则代码将按预期工作。
同样有趣的是,取消定义整个 glob 按预期工作。只是不取消定义子程序本身。
这是一个简短的示例,说明了症状,并与正确的行为形成对比:
#!/usr/bin/env perl
use strict;
use warnings;
# This generates "Not a CODE reference". Why?
sub howdy; *howdy = sub { "Howdy!\n" };
undef &howdy;
eval { howdy };
print $@;
# Undefined subroutine &main::hi called (as expected)
sub hi { "Hi!\n" }
undef &hi;
eval { hi };
print $@;
# Undefined subroutine &main::hello called (as expected)
sub hello; *hello = sub { "Hello!\n" };
undef *hello;
eval { hello };
print $@;
更新:我已经使用 Package::Stash 解决了这个问题(感谢@Ether),但我仍然对它首先发生的原因感到困惑。perldoc perlmod
说:
package main;
sub Some_package::foo { ... } # &foo defined in Some_package
这只是编译时 typeglob 赋值的简写:
BEGIN { *Some_package::foo = sub { ... } }
但它似乎不仅仅是简写,因为两者在取消定义函数后会导致不同的行为。如果有人能告诉我这是(1)不正确的文档,(2)perl中的错误,还是(3)PEBCAK,我将不胜感激。