5

実行時にPerlシンボルテーブルからメソッドを削除する必要があります。を使用してこれを実行しようとしましundef &Square::areaたが、関数は削除されますが、いくつかの痕跡が残ります。具体的には、$square->area()が呼び出されると、Perlは、私が期待している「未定義のサブルーチン&Square :: area called」ではなく、「CODE参照ではない」と文句を言います。

「なぜそれが重要なのですか?関数を削除したのに、なぜそれを呼び出すのですか?」と尋ねるかもしれません。答えは、私がそれを呼んでいないということです、Perlはそうです。SquareはRectangleから継承し、継承チェーンをに渡したいのですが、メソッドが存在しないSquareをスキップしてRectangleのarea()にフォール$square->areaスルー&Rectangle::areaする代わりに、メソッド呼び出しは「コード参照ではありません」で終了します。

奇妙なことに、これは&Square :: areaがtypeglob割り当てによって定義された場合にのみ発生するようです(例*area = sub {...})。関数が標準的なsub area {}アプローチを使用して定義されている場合、コードは期待どおりに機能します。

また興味深いことに、グロブ全体の定義を解除すると、期待どおりに機能します。サブルーチン自体の定義を解除しないでください。

症状を説明し、正しい動作と対比する短い例を次に示します。

#!/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 { ... } }

しかし、関数の定義を解除した後、2つは異なる動作を引き起こすため、これは単なる速記ではないようです。これが(1)誤ったドキュメント、(2)perlのバグ、または(3)PEBCAKのいずれの場合であるかを誰かに教えてもらえれば幸いです。

4

2 に答える 2

7

シンボル テーブルの参照を自分で操作すると、問題が発生することは必至です。幸いなことに、Package::Stashadd_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 = {
              'ハウディ' => *::ハウディ,
              'foo' => *::foo,
    };

ご覧のとおり、'howdy' スロットはまだ存在しています - undefining&howdyは実際には十分なことをしていませ。glob スロットを明示的に削除する必要があります*howdy

于 2011-01-12T22:17:31.110 に答える
2

これが発生する理由は、型グロブを割り当てたからです。

CODE シンボルを削除しても、型グロブの残りの部分は残っているため、howdy を実行しようとするとCODE、型グロブの一部ではない部分がポイントされます。

于 2011-01-12T22:24:18.423 に答える