我如何使用perl中的typeglob做与引用相同的操作?

时间:2011-06-28 11:24:25

标签: perl reference typeglob

$ref = \%hash;
$ref = \@hash;

如何在perl中使用 typeglob 执行相同的操作?

perl解释$$ref{key}的确切步骤是什么?

4 个答案:

答案 0 :(得分:9)

使用*foo{THING}语法,该语法记录在perlref文档的Making References section中。

  

可以使用特殊语法(称为*foo{THING}语法)创建引用。 *foo{THING}返回对*foo中THING位置的引用(这是包含所有foo所有内容的符号表条目。)

$scalarref = *foo{SCALAR};
$arrayref  = *ARGV{ARRAY};
$hashref   = *ENV{HASH};
$coderef   = *handler{CODE};
$ioref     = *STDIN{IO};
$globref   = *foo{GLOB};
$formatref = *foo{FORMAT};

例如:

#! /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";

输出:

Norton
orange

关于问题的第二部分,请添加

print $$ref{Ralph}, "\n";
在Ed产生预期输出后

。编译器为此行生成代码,该代码按以下顺序生成:

  1. 获取$ref
  2. 的填充条目
  3. 获取$ref的东西。
  4. 从第2步中查找哈希中的密钥。
  5. 但是不要相信我的话。要减少产量,请考虑类似的两线:

    my $ref = { Ralph => "Kramden" };
    print $$ref{Ralph};
    

    使用为调试编译的perl运行它会让我们

    $ 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
    [...]

    请注意,它与全局变量略有不同。

    我不确定你的意图是什么,但有一些重要的警告。请注意,typeglob表示符号表条目,因此您不能以这种方式获取词汇,因为它们存在于pad中,而不是符号表中。例如,假设您在上面代码中my @hash = ("splat");的分配之前插入$ref。结果可能让你大吃一惊。

    $ ./prog 
    "my" variable @hash masks earlier declaration in same scope at ./prog line 11.
    Norton
    orange

    关于标量的行为也可能令人惊讶。

      

    *foo{THING}如果尚未使用特定的THING,则会返回undef,但标量除外。如果尚未使用*foo{SCALAR},则$foo会返回对匿名标量的引用。这可能会在将来的版本中发生变化。

    告诉我们您要做的事情,我们将能够为您提供具体,有用的建议。

答案 1 :(得分:6)

如果你问如何获得类型glob的引用,那就是:

my $ref = \*symbol_name_here;

对于它们符号的“文字名称”(即您键入符号的确切名称的位置),而不是变量。但是,你可以这样做:

my $ref = Symbol::qualify_to_ref( $symbol_name );

表示变量符号。但是,上述内容适用于strict,下面更简单的内容不适用:

my $ref = \*{$symbol_name};

Symbol::qualify*的一个好处是,它将包名称作为第二个变量处理。所以......

my $sref = Symbol::qualify_to_ref( $symbol_name, $some_other_package );

\*{$some_other_package.'::'.$symbol_name}做同样的事情,它适用于strict

一旦你有了符号ref,要获得插槽,你必须遵守引用,所以perl并不认为你试图像哈希一样使用它,就像这样。

my $href  = *{ $sref }{HASH};
my $code  = *{ $sref }{CODE};
my $arref = *{ $sref }{ARRAY};
my $io    = *{ $sref }{IO};

另一个

我以不同的方式将你的两个想法放在一起。如果你有一个符号表引用,你可以得到HASH槽,这就像任何其他对哈希的引用一样。所以你可以做到以下几点。

无论

*hash{HASH}->{key}

或者

${ *hash{HASH} }{key}

会奏效。这些更安全,但

( *hash{HASH} || {} )->{key};
${ *hash{HASH} || {} }{key};

如果你想这样做不是直接输入,而是对表格的引用,你会做以下事情:

my $ref   = \*hash;
my $value = *{ $ref }{HASH} && *{ $ref }{HASH}->{key};

注意: %hash绝对需要是一个包变量。只有包变量驻留在符号表中(因此只有subs和@ISA和Exporter变量倾向于在现代符号表中)。词汇变量(声明为my的变量)位于"pad"


更新:

  • 我已经远离使用Symbol了。奇怪的是,即使它是 core ,它似乎也是非标准的,就像Perlers那样 - 并且 - 事物。相反,我在我所谓的“无块”中使用直接方式,就像我可以制作它们一样。

    # 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...
    }
    
  • 我几乎总是使用*STDERR{IO}成语来表示glob文件句柄引用。在现代Perl中,这些通常是对象

    my $fh = *STDERR{IO};
    say blessed( $fh ); # IO::File
    $fh->say( 'Some stuff' );
    

答案 2 :(得分:1)

我认为你不能像使用引用一样对typeglobs做同样的事情(例如词法变量从不涉及类型glob)。你到底想要达到什么目的?

至于$$ref{key},perl按如下方式进行:

  • 第一个$告诉它返回一个标量
  • 在sigil之后存在变量表明该变量必须是引用
  • {...}表示$ref必须是哈希引用

答案 3 :(得分:0)

Perl是一项非常着名的实验性研究:

尝试:

 perl -MO=Terse -e' $ref = \%hash; $ret = $$ref{key}'

或:

 perl -MO=Debug -e' $ref = \%hash; $ret = $$ref{key}'

所有人都将被揭露。如果你有一个调试Perl,你甚至可以这样做:

 perl -Dt -e'$ref = \%hash; $ret = $$ref{key}'