如何使用“子程序引用”作为一个哈希键(How to use a 'subroutine re

2019-09-17 13:58发布

在Perl中,我学习如何取消引用“函数引用”。 但我似乎无法使用子程序引用作为哈希“关键”。

在下面的示例代码,

  1. 我可以创建一个子程序($子参考)的引用,然后取消对它的引用运行子程序($子参考)
  2. 我可以很容易地使用该引用作为散列“值”,然后解除引用该
  3. 但我无法弄清楚如何使用引用作为哈希“关键”。 当我拔出钥匙散列,Perl的解释键作为一个字符串值(不是引用) -我现在明白 (!感谢这个网站的)。 所以,我已经试过哈希::多键,但似乎把它变成一个数组引用。 我希望把它当作一个子程序/码参考,假设这是某种可能吗?

任何其他的想法?

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.

Answer 1:

这是正确的,正常的哈希键只是一个字符串。 事情是不是琴弦强制为他们的字符串表示。

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

领带 ING是惯用的手段来修改行为,但是哈希::多键不帮你,它有不同的用途:正如其名字,你可能有多个键,但也只简单的字符串:

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)'
}

相反,使用领带:: 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));
}


Answer 2:

从perlfaq4 :

我如何使用引用作为哈希键?

(贡献的布莱恩d FOY和Ben莫罗)

哈希键是字符串,所以你不能真正使用参考的关键。 当您尝试这样做,perl的转动参考到它的字符串化的形式(例如,HASH(0xDEADBEEF))。 从那里,你不能回来从字符串化的形式引用,至少没有做你自己一些额外的工作。

请记住,在散列条目仍然会在那里,即使引用变量超出范围,这是完全有可能的Perl在同一地址随后分配一个不同的变量。 这将意味着一个新的变量可能会意外地与旧的价值相关联。

如果你有Perl 5.10或更高版本,而你只是想在以后对存储进行查找的参考值,可以使用核心哈希::的Util :: Fieldhash模块。 这也将重命名处理的按键,如果你使用多线程(这将导致在新地址重新分配所有的变量,改变他们的字串),和垃圾收集的条目时,引用变量超出范围。

如果你确实需要能够得到一个真正的参考,从每个哈希进入回来,你可以使用领带:: RefHash模块,它确实需要的为你工作。

所以它看起来像领带:: RefHash会做你想要什么。 但说实话,我不认为你需要做的是一个特别好的主意。



Answer 3:

你为什么需要它? 比如,如果你需要存储的参数中的散列函数,你可以使用环比:

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} } );
}

但是,你也许可以选择一个更好的钥匙呢。



文章来源: How to use a 'subroutine reference' as a hash key