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

Je *_*Rog 4 perl reference typeglob

$ref = \%hash;
$ref = \@hash;
Run Code Online (Sandbox Code Playgroud)

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

perl需要解释的具体步骤是$$ref{key}什么?

Gre*_*con 9

使用perlref文档*foo{THING}Making References部分中记录的语法.

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

$scalarref = *foo{SCALAR};
$arrayref  = *ARGV{ARRAY};
$hashref   = *ENV{HASH};
$coderef   = *handler{CODE};
$ioref     = *STDIN{IO};
$globref   = *foo{GLOB};
$formatref = *foo{FORMAT};
Run Code Online (Sandbox Code Playgroud)

例如:

#! /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";
Run Code Online (Sandbox Code Playgroud)

输出:

Norton
orange

至于你问题的第二部分,补充一下

print $$ref{Ralph}, "\n";
Run Code Online (Sandbox Code Playgroud)

在Ed产生预期输出之后.编译器为此行生成代码,该代码按以下顺序执行:

  1. 获取pad条目$ref.
  2. 得到$ref的东西.
  3. 在步骤2中查找哈希中的密钥.

但是不要相信我的话.要减少产量,请考虑类似的双线:

my $ref = { Ralph => "Kramden" };
print $$ref{Ralph};
Run Code Online (Sandbox Code Playgroud)

使用为调试编译的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}undef如果尚未使用特定的THING,则返回,除了标量的情况.*foo{SCALAR}如果$foo尚未使用,则返回对匿名标量的引用.这可能会在将来的版本中发生变化.

告诉我们您正在尝试做什么,我们将能够为您提供具体,有用的建议.


Axe*_*man 6

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

my $ref = \*symbol_name_here;
Run Code Online (Sandbox Code Playgroud)

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

my $ref = Symbol::qualify_to_ref( $symbol_name );
Run Code Online (Sandbox Code Playgroud)

对于变量符号.然而,上面的工作strict和下面的更容易的不:

my $ref = \*{$symbol_name};
Run Code Online (Sandbox Code Playgroud)

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

my $sref = Symbol::qualify_to_ref( $symbol_name, $some_other_package );
Run Code Online (Sandbox Code Playgroud)

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

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

my $href  = *{ $sref }{HASH};
my $code  = *{ $sref }{CODE};
my $arref = *{ $sref }{ARRAY};
my $io    = *{ $sref }{IO};
Run Code Online (Sandbox Code Playgroud)

另一个拿

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

*hash{HASH}->{key}
Run Code Online (Sandbox Code Playgroud)

要么

${ *hash{HASH} }{key}
Run Code Online (Sandbox Code Playgroud)

将工作.但这些更安全

( *hash{HASH} || {} )->{key};
${ *hash{HASH} || {} }{key};
Run Code Online (Sandbox Code Playgroud)

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

my $ref   = \*hash;
my $value = *{ $ref }{HASH} && *{ $ref }{HASH}->{key};
Run Code Online (Sandbox Code Playgroud)

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


更新:

  • 我已经远离使用Symbol这么多了.奇怪的是,即使是核心,它似乎不规范的Perlers做的方式- --things.相反,我在我所谓的"无块"中使用直接方式,就像我可以制作它们一样.

    # All I want is one symbol. 
    # Turn strict-refs off, get it, turn it back on.
    my $symb = do { no strict 'refs'; \*{$symbol_name} };
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    {   no strict 'refs';
        *{$package_name.'::'.$symbol_name} = $sub_I_created;
        ... # more reckless symbol table mucking...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 我几乎总是使用这个*STDERR{IO}成语来表示glob文件句柄.在现代Perl中,这些通常是对象.

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