2011-01-12 85 views
5

我需要在運行時從Perl符號表中刪除一個方法。我試圖用undef &Square::area這樣做,它刪除了該功能,但留下了一些痕跡。具體來說,當調用$square->area()時,Perl會抱怨它不是「代碼引用」而不是「未定義的子例程& Square :: area called」,這正是我所期望的。爲什麼這個Perl產生「不是一個CODE引用?」

您可能會問:「爲什麼這麼重要?您刪除了該功能,您爲什麼要這樣做?」答案是我不叫它,Perl是。 Square從Rectangle繼承,我希望繼承鏈通過$square->area&Rectangle::area,但不是跳過方法不存在的Square,然後進入Rectangle的區域(),而是在方法調用中使用「Not a CODE reference 「。

奇怪的是,這似乎只發生在& 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 [email protected]; 

# Undefined subroutine &main::hi called (as expected) 
sub hi { "Hi!\n" } 
undef &hi; 
eval { hi }; 
print [email protected]; 

# Undefined subroutine &main::hello called (as expected) 
sub hello; *hello = sub { "Hello!\n" }; 
undef *hello; 
eval { hello }; 
print [email protected]; 

更新:因爲我已經解決了使用套票:藏匿處(感謝@Ether)這個問題,但我米仍然爲什麼它首先發生困惑。 perldoc perlmod說:

package main;

sub Some_package::foo { ... } # &foo defined in Some_package

這僅僅是在編譯時一個類型團賦值速記:

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

但看來,它不是」 t 只是速記,因爲這兩者在定義函數後會導致不同的行爲。如果有人能告訴我這是(1)不正確的文檔,(2)perl錯誤還是(3)PEBCAK,我會很感激。

+0

你從哪裏得到'undef&Square :: area`會刪除子程序的想法?不是攻擊,只是好奇... – Ether 2011-01-12 22:14:29

+3

從`perldoc -f undef`。他們給出的例子是`undef &mysub;`,但它也適用於限定名稱。 – KingPong 2011-01-12 22:26:04

回答

7

自己操縱符號表引用必然會讓你陷入困境,因爲有許多小事很難糾正。幸運的是,有一個模塊可以完成所有繁重的工作,Package::Stash - 只需根據需要調用方法add_package_symbolremove_package_symbol即可。

你可能想要檢查的另一個好方法安裝程序是Sub::Install - 如果你想生成很多類似的功能,特別好。

至於爲什麼你的做法是不正確的,讓我們來看看符號表中刪除代碼引用後:

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

undef &howdy; 
eval { howdy }; 
print [email protected]; 

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

打印(有刪節):

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

正如你所看到的'howdy'slot is present present - undefining &howdy does not actually do anything 夠了。您需要明確刪除glob插槽*howdy

2

它發生的原因正是因爲您分配了一個typeglob。

當您刪除CODE符號時,其餘的typeglob仍然存在,所以當您嘗試執行howdy時,它將指向非CODE一塊typeglob。

相關問題