[英]Why does this Perl produce “Not a CODE reference?”
我需要在運行時從Perl符號表中刪除一個方法。 我嘗試使用undef &Square::area
執行此操作,這會刪除該功能但會留下一些痕跡。 具體來說,當調用$square->area()
,Perl會抱怨它是“不是CODE引用”而不是“Undefined subroutine&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,我會很感激。
操縱符號表引用自己必然會讓你陷入困境,因為有很多很難找到的小東西。 幸運的是,有一個模塊可以為你完成所有繁重的工作, Package :: Stash - 所以只需要根據需要調用它的方法add_package_symbol
和remove_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 = { 'howdy' => *::howdy, 'foo' => *::foo, };
正如你所看到的那樣,'howdy'插槽仍然存在 - &howdy
實際上沒有做足夠的
事情
。 你需要顯式刪除glob插槽, *howdy
。
它發生的原因正是因為你分配了一個typeglob。
當你刪除CODE符號時,其余的typeglob仍然是揮之不去的,所以當你嘗試執行howdy時它會指向非CODE
的typeglob。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.