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

Jon*_*Jon 2 perl

我正在审查这个问题,特别是埃里克斯特罗姆先生的回应,并对其中一部分更"神奇"的元素提出了疑问.请查看上下文的链接问题,因为我只是想了解这个块的内部部分:

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

因此,它循环超过三个单词,将每个单词分成两个变量,$sigil并且$type.该if {}块是什么我不理解.我怀疑其中的部分( .. )正在获得对内容中的内容的符号引用$glob{$type}...必须有一些"魔法"(我尚未理解的潜在机制的一些深奥元素)依赖于那里来确定其类型"尖头"数据?

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

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

Axe*_*man 5

迭代的元素是字符串。由于循环顶部没有词法变量,元素变量是$_。它在整个循环中保留该值。这些字符串中只有一个具有字面意义的美元符号,因此我们要区分'$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 );
Run Code Online (Sandbox Code Playgroud)

结果散列将是:

{ '$a' => 'boo'
, '%a' => { One => 1, Two => 2 }
, '@a' => [ 1, 2, 3 ]
};
Run Code Online (Sandbox Code Playgroud)

同时,glob 可以被认为是这样的:

a => 
    { SCALAR => \'boo'
    , ARRAY  => [ 1, 2, 3 ]
    , HASH   => { One => 1, Two => 2 }
    , CODE   => undef
    , IO     => undef 
    , GLOB   => undef
    };
Run Code Online (Sandbox Code Playgroud)

所以特地回答你的问题。

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

如果一个插槽没有被使用,它就是 undef。因此$ref将被分配一个或参考undef,其计算结果为true作为参考和false作为undef。因此,如果我们有一个引用,则将该 glob 插槽的值存储到哈希中,如果它是“容器类型”,则获取存储在哈希中的引用,但如果它是标量,则获取该值。它与哈希中的键$sigil . $name一起存储%vars


Bor*_*din 5

你已经找到了Perl语言中最神秘的部分之一,我可以通过引用brian d foy优秀的Mastering Perl中的符号表和Typeglobs解释.还需要注意的是有页面,最相关的,其中是底部的Perl的自己的文档中的有关章节进一步引用类型团和文件句柄在.perldata

从本质上讲,perl符号表的工作方式是每个都有一个"存储" - 一个"符号表哈希" - 其名称与包相同,但带有一对尾随分号.因此main调用默认包的存储%main::.如果你运行这个简单的程序

perl -E"say for keys %main::"
Run Code Online (Sandbox Code Playgroud)

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

用于藏匿元素要引用类型团,而这又是散列但具有对应于不同的数据类型的密钥,SCALAR,ARRAY,HASH,CODE等,以及那些对与该类型和标识符的数据项的引用值.

假设你定义一个标量变量$xx,或者更完整,$main:xx

our $xx = 99;
Run Code Online (Sandbox Code Playgroud)

现在藏匿main%main::,并与该标识符的所有数据项的类型团xx被引用$main::{xx}的话,因为印记的类型团是一个明星*在相同的方式,标标识符有一块钱$,我们可以反引用本作*{$main::{xx}}.要获取对具有标识符的标量变量的引用xx,可以使用SCALAR字符串赋值来索引此typeglob *{$main::{xx}}{SCALAR}.再一次,这是我们所追求的变量的引用,所以要收集它的值,它需要再次解除引用,如果你写的话

say ${*{$main::{xx}}{SCALAR}};
Run Code Online (Sandbox Code Playgroud)

然后你会看到99.

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

my $type = 'SCALAR';
my $glob = $main::{xx};
my $ref  = *$glob{$type};
Run Code Online (Sandbox Code Playgroud)

现在,如果我们say $ref得到SCALAR(0x1d12d94)或类似,这是$main::xx以前的参考,打印$$ref将按99预期显示.

随后的赋值@vars是直截了当的Perl,我认为你不应该理解一旦你得到包符号表是一个典型的东西,或者实际上只是一个散列哈希的原则.