How to use a subroutine reference as a hash key

In Perl, I learn how to look up subroutine links. But I can not use the subroutine link as a hash key.

In the following code example

  • I can create a link to the subroutine ($ subref) and then dereference it to run the subroutine (& $ subref)
  • I can use the link as a hash value and then easily dereference that
  • But I can’t understand how to use the link as a hash key. When I pull the key from the hash, Perl interprets the key as a string value (not a link), which I now understand (thanks to this site!). So I tried Hash :: MultiKey, but it seems to have turned it into an array reference. I want to consider it as a subroutine / code link, considering it possible?

Any other ideas?

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

This is what returns:

 hello bob and sue hello bob and sue Ref type is: ARRAY Not a CODE reference at d:\temp\test.pl line 21. 
+2
reference subroutine perl dereference hash
source share
3 answers

That's right, a regular hash key is just a string. Things that are not strings are forced into their string representation.

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

Tie ing is the usual way to change this behavior, but Hash :: MultiKey will not help you, it has a different purpose: as the name says, you can have several keys, but again only simple lines:

 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, ie simple strings say 'List elements produced by array-dereferencing the key are:'; say $_ for @{ $key }; # 'CODE(0x8d27f0)' } 

Use Tie :: RefHash instead . (Criticism of code: prefer this syntax with an arrow -> to dereference 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)); } 
+2
source share

From perlfaq4 :

How to use the link as a hash key?

(contributed by brian d foy and Ben Morrow)

Hash keys are strings, so you cannot use a link as a key. When you try to do this, perl turns the link into its gated (for example, HASH (0xDEADBEEF)). From there you cannot return a link from a string form, at least without any additional work on its own.

Remember that a hash entry will still be present even if the reference variable is out of scope and that it is completely possible for Perl to subsequently allocate another variable to the same address. This means that the new variable may be randomly associated with the value for the old.

If you have Perl 5.10 or later, and you just want to keep the value against the search link later, you can use the Hash :: Util :: Fieldhash module kernel. This will also lead to renaming the keys if you use multiple threads (which leads to the fact that all variables are redistributed to new addresses, change their structure) and garbage collection when the reference variables go out of scope.

If you really need to get a real link from each hash entry, you can use the Tie :: RefHash module, which does the job you need.

So this looks like Tie :: RefHash will do what you want. But honestly, I don’t think that what you want to do is a particularly good idea.

+1
source share

Why do you need this? If you, for example, need to save parameters for functions in a hash, you can use 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} } ); } 

But then you can probably choose the best key.

0
source share

All Articles