开发者

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 as foo).

$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:

  1. Fetch the pad entry for $ref.
  2. Get $ref's thingie.
  3. 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} returns undef 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}'
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜