How do I dereference a hash that's been returned from a method of a class?
I have a class with a method that returns a hash. Ordinarily, I would get the result like so:
%resp = $myclass->sub($foo);
And then access members of the returned hash like this:
$resp{key}{subkey};
in the case of a 2d hash.
I figure there must be a way to combine this into a single, elegant line, something like this:
$myclass->sub($foo)->{key}{subkey}
This obviously is not dereferenced properly as Perl returns this when trying to run the code:
Can't use string开发者_如何学Python ("1/8") as a HASH ref
In trying random dereferencing sequences, from looking "References quick reference" on Perlmonks, I came up with the following, which Perl does not complain about, but also does not return what I'm looking for:
$%{$myclass->sub($foo)}->{key}{subkey}
Can somebody tell me what the magic dereferencing escape sequence is to do this?
What you are trying to do is neither elegant nor advisable. You have somehow managed to invoke the routine in scalar context (that's what the "1/8"
corresponds to).
Return a hash reference.
Now, take a look at:
#!/usr/bin/perl
package My::Mine;
use strict; use warnings;
sub test {
my %h = (
a => { z => 1},
b => { y => 2},
);
return %h;
}
package main;
use strict; use warnings;
my $class = 'My::Mine';
print { $class->test }->{a}{z}, "\n";
That will not work. Instead, you will have to do:
print +{ $class->test }->{a}{z}, "\n";
Now, that's elegant (Not!) See perldoc -f print.
Long story short, return a reference to the hash.
Note that the fresh anonymous hash you are constructing is not free. Nor is the cost of returning a hash as a flat list from a subroutine.
Changing the sub to return a hash reference would work best, but to get the functionality you are looking for:
{ $myclass->sub($foo) }->{key}{subkey}
which will create a hash reference from the list returned by sub
, and then immediately dereference it
Edit: The advantage to returning a hashref from your sub rather than a hash (as a list) is largely one of performance. In the hashref case, the hash is created once, and then accessed. In the list case, the hash is created, then converted into a list, then created again, and then dereferenced. For small hashes this wont take too much time, but for larger ones, it is just unnecessary work for the runtime. Basically, if you plan to use the data as a list in some places, and as a hash in others, returning the hash as a list is ok. But if you are always planning to use it as a hash, returning the reference is clearer and faster.
I'd return a HASH reference from the sub instead. Otherwise (probably) your hash is turned into a LIST then into a HASH again for no reason:
sub mysub() {
...
return \%myhash;
}
There is less copying involved when returning the reference hence more efficient.
Just return a hashref instead of a hash:
$myclass->sub($foo)->{key}->{subkey}
If you always want to just get one subkey, write a short subroutine to do that for you and forget about golfing your line. One advantage is that you can easily add some sanity checking:
sub get_subkey {
my( $class, $arg, $key, $subkey ) = @_;
my $hashref = $class->method( $arg );
return unless ref $hashref;
return $hashref->{$key}{$subkey};
}
精彩评论