How do I do the same thing as reference using typeglob in perl?
$ref = \%hash;
$ref = \@h开发者_开发百科ash;
How do I do the same thing as reference using typeglob in perl?
What's the exact steps perl takes to interpret $$ref{key}
?
Use the *foo{THING}
syntax, which is documented in the Making References section of the perlref documentation.
A reference can be created by using a special syntax, lovingly known as the
*foo{THING}
syntax.*foo{THING}
returns a reference to the THING slot in*foo
(which is the symbol table entry which holds everything known asfoo
).$scalarref = *foo{SCALAR}; $arrayref = *ARGV{ARRAY}; $hashref = *ENV{HASH}; $coderef = *handler{CODE}; $ioref = *STDIN{IO}; $globref = *foo{GLOB}; $formatref = *foo{FORMAT};
For example:
#! /usr/bin/env perl
use strict;
use warnings;
our %hash = (Ralph => "Kramden", Ed => "Norton");
our @hash = qw/ apple orange banana cherry kiwi /;
my $ref;
$ref = *hash{HASH};
print $ref->{Ed}, "\n";
$ref = *hash{ARRAY};
print $ref->[1], "\n";
Output:
Norton orange
As for the second part of your question, adding
print $$ref{Ralph}, "\n";
after Ed produces the expected output. The compiler generates code for this line that goes through the following sequence:
- Fetch the pad entry for
$ref
. - Get
$ref
's thingie. - Look up the key in the hash from step 2.
But don't take my word for it. To cut down the volume of output, consider a similar two-liner:
my $ref = { Ralph => "Kramden" };
print $$ref{Ralph};
Running it with a perl compiled for debugging gets us
$ debugperl -Dtls ref [...] (ref:1) nextstate => (ref:2) pushmark => * (ref:2) padsv($ref) # STEP 1 => * \HV() (ref:2) rv2hv # STEP 2 => * HV() (ref:2) const(PV("Ralph"\0)) # STEP 3a => * HV() PV("Ralph"\0) (ref:2) helem # STEP 3b => * PV("Kramden"\0) (ref:2) print => SV_YES (ref:2) leave [...]
Note that it's slightly different for globals.
I'm not sure what your larger intent is, but there are some important caveats. Note that a typeglob represents a symbol table entry, so you can't get at lexicals this way because they live in pads, not the symbol table. For example, say you insert my @hash = ("splat");
just before the assignments to $ref
in the code above. The result may surprise you.
$ ./prog "my" variable @hash masks earlier declaration in same scope at ./prog line 11. Norton orange
The behavior with respect to scalars may also be surprising.
*foo{THING}
returnsundef
if that particular THING hasn't been used yet, except in the case of scalars.*foo{SCALAR}
returns a reference to an anonymous scalar if$foo
hasn't been used yet. This might change in a future release.
Tell us what you're trying to do, and we'll be able to give you specific, useful suggestions.
If you're asking how you get a reference to a type glob, it's just:
my $ref = \*symbol_name_here;
For a "literal name" of the symbol, (that is where you type in the exact name of the symbol), and not a variable. But, you can do this:
my $ref = Symbol::qualify_to_ref( $symbol_name );
for a variable symbol. However, the above works with strict
and the easier one below doesn't:
my $ref = \*{$symbol_name};
One of the nice things about Symbol::qualify*
, is that it handles package names as the second variable. So...
my $sref = Symbol::qualify_to_ref( $symbol_name, $some_other_package );
does the same thing as \*{$some_other_package.'::'.$symbol_name}
and it works with strict
.
Once you have the symbol ref, to get the slot, you have to deference the reference, so perl does not think you're trying to use it as a hash, like so.
my $href = *{ $sref }{HASH};
my $code = *{ $sref }{CODE};
my $arref = *{ $sref }{ARRAY};
my $io = *{ $sref }{IO};
Another Take
I put your two ideas together in a different way. If you have a symbol table reference, you can get the HASH
slot and that is a reference just like any other reference to a hash. So you can do the following.
Either
*hash{HASH}->{key}
Or
${ *hash{HASH} }{key}
will work. These are safer, though
( *hash{HASH} || {} )->{key};
${ *hash{HASH} || {} }{key};
If you want to do this not with a direct entry, but a reference into the table, you would do the following:
my $ref = \*hash;
my $value = *{ $ref }{HASH} && *{ $ref }{HASH}->{key};
NOTE: %hash
absolutely needs to be a package variable. Only package variables reside in the symbol table (so only subs and @ISA
and Exporter variables tend to be in modern symbol tables). Lexical variables (those declared my
) reside in the "pad".
UPDATE:
I have gotten away from using
Symbol
so much. Curiously, even though it is core, it seems non-standard in the way Perlers do--and see--things. Instead, I use the direct way in what I call "no-blocks", as localized as I can make them.# All I want is one symbol. # Turn strict-refs off, get it, turn it back on. my $symb = do { no strict 'refs'; \*{$symbol_name} };
OR
{ no strict 'refs'; *{$package_name.'::'.$symbol_name} = $sub_I_created; ... # more reckless symbol table mucking... }
I almost always use the
*STDERR{IO}
idiom for a glob file handle reference. In modern Perl, these are usually objects.my $fh = *STDERR{IO}; say blessed( $fh ); # IO::File $fh->say( 'Some stuff' );
I don't think you can do the exact same thing with typeglobs as you can do with references (for example lexical variables never involve a type glob). What do you want to achieve in the end?
As for $$ref{key}
, perl proceeds as follows:
- the first $ tells it that a scalar is returned
- the presence of a variable after a sigil indicates that that variable must a reference
- the
{...}
indicates that$ref
must be a hash reference
Perl is remarkably and famously experimental:
Try:
perl -MO=Terse -e' $ref = \%hash; $ret = $$ref{key}'
or:
perl -MO=Debug -e' $ref = \%hash; $ret = $$ref{key}'
and all will be revealed. If you have a debugging Perl, you can even do:
perl -Dt -e'$ref = \%hash; $ret = $$ref{key}'
精彩评论