2

Perlでは、「サブルーチン参照」を逆参照する方法を学んでいます。しかし、サブルーチン参照をハッシュ「キー」として使用することはできないようです。

次のサンプルコードでは、

  1. サブルーチン($ subref)への参照を作成し、それを逆参照してサブルーチン(&$ subref)を実行できます。
  2. 参照をハッシュ'値'として使用し、それを簡単に逆参照できます。
  3. しかし、参照をハッシュ「キー」として使用する方法がわかりません。ハッシュからキーを引き出すと、Perlはキーを文字列値(参照ではない)として解釈します-これは今では理解できます(このサイトに感謝します!)。だから私はHash::MultiKeyを試しましたが、それはそれを配列参照に変えているようです。これがどういうわけか可能であると仮定して、それをサブルーチン/コード参照として扱いたいですか?

他のアイデアはありますか?

use strict;
#use diagnostics;
use Hash::MultiKey;    

my $subref = \&hello;

#1: 
&$subref('bob','sue');               #okay

#2:
my %hash;
$hash{'sayhi'}=$subref;
&{$hash{'sayhi'}}('bob','sue');      #okay

#3: 
my %hash2;
tie %hash2, 'Hash::MultiKey';
$hash2{$subref}=1;
foreach my $key (keys %hash2) {
  print "Ref type is: ". ref($key)."\n";
  &{$key}('bob','sue');              # Not okay 
}

sub hello {
    my $name=shift;
    my $name2=shift;
    print "hello $name and $name2\n";
}

これが返されるものです:

hello bob and sue
hello bob and sue
Ref type is: ARRAY
Not a CODE reference at d:\temp\test.pl line 21.
4

3 に答える 3

2

それは正しいです、通常のハッシュキーは文字列だけです。文字列ではないものは、文字列表現に強制されます。

my $coderef = sub { my ($name, $name2) = @_; say "hello $name and $name2"; };
my %hash2 = ( $coderef => 1, );
print keys %hash2;  # 'CODE(0x8d2280)'

結び付けはその動作を変更する通常の手段ですが、Hash :: MultiKey役に立ちません。目的は異なります。名前が示すように、複数のキーがある場合がありますが、これも単純な文字列のみです。

use Hash::MultiKey qw();
tie my %hash2, 'Hash::MultiKey';
$hash2{ [$coderef] } = 1;
foreach my $key (keys %hash2) {
    say 'Ref of the key is: ' . ref($key);
    say 'Ref of the list elements produced by array-dereferencing the key are:';
    say ref($_) for @{ $key }; # no output, i.e. simple strings
    say 'List elements produced by array-dereferencing the key are:';
    say $_ for @{ $key }; # 'CODE(0x8d27f0)'
}

代わりに、Tie::RefHashを使用してください。(コード批評:->coderefを逆参照するための矢印の付いたこの構文を好む。)

use 5.010;
use strict;
use warnings FATAL => 'all';
use Tie::RefHash qw();

my $coderef = sub {
    my ($name, $name2) = @_;
    say "hello $name and $name2";
};

$coderef->(qw(bob sue));

my %hash = (sayhi => $coderef);
$hash{sayhi}->(qw(bob sue));

tie my %hash2, 'Tie::RefHash';
%hash2 = ($coderef => 1);
foreach my $key (keys %hash2) {
    say 'Ref of the key is: ' . ref($key);   # 'CODE'
    $key->(qw(bob sue));
}
于 2012-05-29T09:02:35.957 に答える
1

perlfaq4から:

参照をハッシュキーとして使用するにはどうすればよいですか?

(brian dfoyとBenMorrowによる寄稿)

ハッシュキーは文字列であるため、実際には参照をキーとして使用することはできません。これを行おうとすると、perlは参照を文字列形式に変換します(たとえば、HASH(0xDEADBEEF))。そこから、少なくとも自分で追加の作業を行わずに、文字列化されたフォームから参照を取り戻すことはできません。

参照された変数がスコープ外になった場合でも、ハッシュのエントリは引き続き存在し、Perlが後で同じアドレスに別の変数を割り当てることは完全に可能であることに注意してください。これは、新しい変数が誤って古い値に関連付けられる可能性があることを意味します。

Perl 5.10以降を使用していて、後で検索するために参照に対して値を保存したい場合は、コアのHash :: Util::Fieldhashモジュールを使用できます。これは、複数のスレッドを使用する場合のキーの名前変更(すべての変数が新しいアドレスに再割り当てされ、文字列化が変更される)、および参照される変数がスコープ外になったときにエントリをガベージコレクションすることも処理します。

実際に各ハッシュエントリから実際の参照を取得できるようにする必要がある場合は、Tie::RefHashモジュールを使用できます。これは必要な作業を行います。

つまり、Tie::RefHashはあなたが望むことをするように見えます。でも正直なところ、あなたがやりたいことは特に良い考えではないと思います。

于 2012-05-29T08:39:43.753 に答える
0

なぜあなたはそれが必要なのですか?たとえば、関数のパラメータをハッシュに格納する必要がある場合は、HoHを使用できます。

my %hash;
$hash{$subref} = { sub => $subref,
                   arg => [qw/bob sue/],
                 };
foreach my $key (keys %hash) {
    print "$key: ref type is: " . ref($key) . "\n";
    $hash{$key}{sub}->( @{ $hash{$key}{arg} } );
}

しかし、とにかく、おそらくより良いキーを選択することができます。

于 2012-05-29T08:38:47.460 に答える