【发布时间】:2011-01-12 22:08:21
【问题描述】:
我需要在运行时从 Perl 符号表中删除一个方法。我尝试使用undef &Square::area 来执行此操作,它确实删除了该函数但留下了一些痕迹。具体来说,当调用 $square->area() 时,Perl 抱怨它是“不是代码引用”而不是“未定义的子例程 &Square::area called”,这是我所期望的。
你可能会问,“为什么重要?你删除了这个函数,你为什么要调用它?”答案是我不叫它,Perl 是。 Square 继承自 Rectangle,我希望继承链将 $square->area 传递给 &Rectangle::area,但不是跳过该方法不存在的 Square 然后落入 Rectangle 的 area(),方法调用以“不是代码参考。”
奇怪的是,这似乎只发生在 &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,我将不胜感激。
【问题讨论】:
-
你从哪里得知
undef &Square::area会删除一个子程序?不是攻击,只是好奇…… -
来自
perldoc -f undef。他们给出的例子是undef &mysub;,但它也适用于限定名称。 -
替代“你可能会问”的问题。你为什么首先定义 &Square::area ?为什么不 [重新] 定义 &Square::area 以委托给它的超类?
-
@JB:这是用于测试设备,而不是实时代码。
标签: perl subroutine symbol-tables typeglob