需要帮助理解脚本部分(globs和参考)

时间:2014-10-09 15:38:18

标签: perl

我正在审核this question,特别是来自埃里克斯特罗姆先生的response,并且对于一部分更神奇的"内在的元素。请查看上下文链接的问题,因为我只想了解此块的内部部分:

for (qw($SCALAR @ARRAY %HASH)) {
    my ($sigil, $type) = /(.)(.+)/;
    if (my $ref = *$glob{$type}) {
        $vars{$sigil.$name} = /\$/ ? $$ref : $ref
    }
}

因此,它会循环显示三个单词,将每个单词分成两个变量,$sigil$typeif {}块是我不理解的。我怀疑( .. )中的部分是$glob{$type}内的内容的象征性引用...必须有一些"魔法" (我不理解的潜在机制的一些深奥元素)依靠那里来确定"指向"的类型。数据?

下一行也部分令人费解。在我看来,我们正在分配vars哈希,但rhs在做什么?我们没有在最后一次操作中分配$_$ref已分配),那么在/\$/块中进行比较的是什么?我的猜测是,如果我们处理标量(虽然我无法辨别出它们是什么),我们将$ref var deref并将其直接存储在散列中,否则,我们存储引用。

所以,只是想看看这三行中发生了什么的故事。非常感谢!

2 个答案:

答案 0 :(得分:5)

你已经找到了Perl语言中最神秘的部分之一,我可以通过Symbol Tables and Typeglobs来自brian d foy的优秀掌握Perl 来引用你最好的解释。另请注意,页面底部还提供了Perl自己文档的相关部分,其中最相关的部分是perldata中的Typeglobs and Filehandles

基本上,perl符号表的工作方式是每个都有一个“stash” - 一个“符号表哈希” - 其名称与包装但带有一对拖尾分号。因此,默认包main的存储称为%main::。如果你运行这个简单的程序

perl -E"say for keys %main::"

您将看到所有熟悉的内置标识符。

存储元素的是对 typeglobs 的引用,它们也是哈希值,但具有与不同数据类型对应的键SCALAR,{ {1}},ARRAYHASH等以及对具有该类型和标识符的数据项的引用值。

假设您定义了一个标量变量CODE,或者更全面地定义了$xx

$main:xx

现在our $xx = 99; 包的存储main%main::引用了标识为xx的所有数据项的typeglob所以,因为typeglobs的 sigil 是星号$main::{xx},就像标量标识符有一个美元*一样,我们可以将其取消引用为$。要获取对标识为*{$main::{xx}}标量变量的引用,可以使用xx字符串对此类型地址进行索引,并提供SCALAR。再一次,这是我们所追求的变量的引用,所以要收集它的值,它需要再次引用,如果你写了

*{$main::{xx}}{SCALAR}

然后您会看到say ${*{$main::{xx}}{SCALAR}};

当用单个语句写出来时,这可能看起来有点复杂,但在拆分时它是相当复杂的。您的问题中的代码将变量99设置为对typeglob的引用,对应于$glob

$main::xx

现在,如果我们my $type = 'SCALAR'; my $glob = $main::{xx}; my $ref = *$glob{$type}; 获得say $ref或类似内容,这是SCALAR(0x1d12d94)之前的引用,则打印$main::xx将按预期显示$$ref

随后对99的赋值是直截了当的Perl,我认为一旦你得到一个包符号表是一个典型的东西,或者实际上只是一个哈希的原则,你就不会有任何问题。哈希。

答案 1 :(得分:4)

迭代的元素是 strings 。由于我们在循环顶部没有词法变量,因此元素变量为$_。它在整个循环中保留了这个价值。这些字符串中只有一个具有文字美元符号,因此我们告诉'$SCALAR'与其他案例之间的区别。

所以它正在做的是从包级typeglob中获得3个插槽(有时缩短,歧义为“glob”)。 *g{SCALAR}*g{ARRAY}*g{HASH}。 glob存储散列和数组作为引用,因此我们只是将引用存储到散列中。但是,glob将标量存储为标量的引用,因此需要取消引用,才能存储为标量。

所以如果你有一个glob *a并且在你的包中你有:

our $a = 'boo';
our @a = ( 1, 2, 3 );
our %a = ( One => 1, Two => 2 );

产生的哈希值为:

{ '$a' => 'boo'
, '%a' => { One => 1, Two => 2 }
, '@a' => [ 1, 2, 3 ]
};

同时可以认为glob看起来像这样:

a => 
    { SCALAR => \'boo'
    , ARRAY  => [ 1, 2, 3 ]
    , HASH   => { One => 1, Two => 2 }
    , CODE   => undef
    , IO     => undef 
    , GLOB   => undef
    };

所以要专门回答你的问题。

if (my $ref = *$glob{$type}) {
    $vars{$sigil.$name} = /\$/ ? $$ref : $ref
}

如果没有使用插槽,则它是undef。因此,为$ref分配了引用或undef,其评估为true作为参考,false评估为undef。所以 if 我们有一个引用,然后将该glob时隙的值存储到哈希中,将参考存储在哈希中,如果它是一个“容器类型”,但如果它是一个“容器类型”则取值标量。并且它与$sigil . $name哈希中的密钥%vars一起存储。