perl - 为什么这个 Perl 会产生 "Not a CODE reference?"

标签 perl subroutine symbol-tables typeglob

我需要在运行时从 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

This is just a shorthand for a typeglob assignment at compile time:

BEGIN { *Some_package::foo = sub { ... } }



但它似乎不仅仅是简写,因为两者在取消定义函数后会导致不同的行为。如果有人能告诉我这是(1)不正确的文档,(2)perl中的错误,还是(3)PEBCAK,我将不胜感激。

最佳答案

自己操作符号表引用肯定会给你带来麻烦,因为有很多小事很难做对。幸运的是,有一个模块可以为您完成所有繁重的工作,Package::Stash -- 所以只要调用它的方法add_package_symbolremove_package_symbol如所须。

您可能想要查看的另一个好方法安装程序是 Sub::Install -- 如果你想生成很多类似的函数,特别好。

至于为什么你的做法不正确,我们来看看删除代码引用后的符号表:

sub foo { "foo!\n"}
sub howdy; *howdy = sub { "Howdy!\n" };

undef &howdy;
eval { howdy };
print $@;

use Data::Dumper;
no strict 'refs';
print Dumper(\%{"main::"});

打印品(删节):

$VAR1 = {
'你好' => *::你好,
'foo' => *::foo,
};

如您所见,'howdy' 插槽仍然存在 - 未定义 &howdy实际上并没有做足够的事情。您需要显式删除 glob 插槽 *howdy .

关于perl - 为什么这个 Perl 会产生 "Not a CODE reference?",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4674560/

相关文章:

perl - 用 Perl 从网络驱动器读取文件

perl - 如何在Test::Class中使用Moose?

function - Fortran - 从子例程返回匿名函数

c - 在 C 中访问 ELF 符号表

perl - 以可读方式打印 (Perl)

python - 你如何将这个正则表达式习语从 Perl 翻译成 Python?

fortran - Fortran 子例程参数列表中的星号 * 符号是什么意思?

Java - 在类方法中定义方法/函数/子例程

linux-kernel - 确定剥离的 Linux 内核镜像的加载地址和入口点

c - 堆栈上局部变量的 GCC 符号表