【问题标题】:How do I do the same thing as reference using typeglob in perl?如何在 perl 中使用 typeglob 做与引用相同的事情?
【发布时间】:2011-06-28 11:24:24
【问题描述】:
$ref = \%hash;
$ref = \@hash;

如何在 perl 中使用 typeglob 做与引用相同的事情?

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

【问题讨论】:

  • 您的第一个问题(我认为是无意中)与您的第二个问题无关。 $$ref{key}$ref->{key} 相同,仅在您的第一次分配中会出现这种情况,但与“哈希”的符号表条目无关,更多的是与您可以保存对哈希的引用。
  • How do I do the same thing as reference using typeglob in perl? 人们已经阅读了这个问题的各种内容,但我无法理解它。你能完全改写它吗?

标签: perl reference typeglob


【解决方案1】:

使用 *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";

输出:

诺顿
橙色

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

print $$ref{Ralph}, "\n";

在 Ed 产生预期的输出之后。编译器为该行生成代码,该代码经过以下顺序:

  1. 获取 $ref 的 pad 条目。
  2. 获取$ref 的东西。
  3. 在第 2 步的哈希中查找键。

但不要相信我的话。要减少输出量,请考虑类似的两线:

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

使用为调试而编译的 perl 运行它可以帮助我们

$ debugperl -Dtls 参考
[...]
(参考:1)下一个状态
    =>
(参考:2)pushmark
    => *
(ref:2) padsv($ref) # 第 1 步
    => * \HV()
(ref:2) rv2hv # 第 2 步
    => * 高压()
(ref:2) const(PV("Ralph"\0)) # STEP 3a
    => * HV() PV("拉尔夫"\0)
(ref:2) helem # STEP 3b
    => * PV("克拉姆登"\0)
(参考:2)打印
    => SV_YES
(ref:2) 离开
[...]

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

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

$ ./prog
“我的”变量 @hash 掩盖了 ./prog 第 11 行相同范围内的早期声明。
诺顿
橙色

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

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

告诉我们您想要做什么,我们将能够为您提供具体、有用的建议。

【讨论】:

  • 这解释了当数组/哈希被定义为our时的情况,当它们是my时呢?
  • @Je Rog Lexicals(用my 声明)包含在我的答案的警告部分中。简短的回答是你不能。您想要破解 typeglob 的代码的总体意图是什么?
【解决方案2】:

如果您要问如何获得对类型 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 了。奇怪的是,即使它是 核心,它似乎 非标准 以 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} };
    

    {   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' );
    

【讨论】:

  • 如果%hash 定义为my 会怎样?
  • @Je Rog,它不在符号表中,而是在“pad”中。接地见PadWalker
【解决方案3】:

我不认为你可以用 typeglobs 做与引用一样的事情(例如,词法变量从不涉及类型 glob)。你最终想达到什么目标?

对于$$ref{key},perl 进行如下:

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

【讨论】:

【解决方案4】:

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}'

【讨论】:

  • 嗯,有很多。额外的标志将启用一些 perl 调试,这应该可以帮助您回答您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多