需要帮忙解释这段 Perl 代码。

3

我对这个小代码片段感到困惑

my $ref = \@{$seq->{$label}{$ARGV[4]}};

能否帮助我解读一下?


(注:该代码涉及Perl语言中的引用和哈希表操作,其中$seq、$label和$ARGV[4]是变量名)
3个回答

5
让我们这样重写它。
my $ref = \@{

    $seq->{ $label }{ $ARGV[4] }

}

外层的my $ref =是一个赋值语句。我认为这很清楚。

然后@{ ... }解引用括号中的内容作为数组,\则取该数组的引用。引用取消了解引用,所以它与下面的表达式是相同的

my $ref = $seq->{ $label }{ $ARGV[4] }

除非内容是数组的引用,否则取消引用会导致程序报错:

不是数组引用

现在我们有:

$seq->{ $label }{ $ARGV[4] }

这段代码使用$seq作为哈希表的引用,将$label作为第一级键,$ARGV[4](第五个命令行参数)作为第二级键。

这段代码由一个我会慷慨地称之为糟糕程序员的人编写。我怀疑它的目的是检查哈希值是否为数组引用,并且至少应该将$ARGV[4]复制到一个命名变量中以使其含义清晰。


@Tom:那不是真的,正如我在早些时候对Matt Jacob的评论中所解释的。尝试这个 perl -E '$r = [ qw/ A B C / ]; $r2 = \@$r; $r2->[2] = q{X}; say qq{$r @$r $r2 @$r2}' 输出 ARRAY(0x72c530) A B X ARRAY(0x72c530) A B X。你可能在想 $ref2 = [ @$ref ],它确实会产生一个浅拷贝。 - Borodin

2
  • $seq是一个哈希引用
  • $seq->{$label}返回解引用哈希中$label键的值
  • 该值是另一个哈希,从中获取$ARGV[4]键的值
    • @ARGV是命令行参数的数组,$ARGV[4]是索引为4的元素
  • 所有这些都返回一个数组引用,它被@{...}解引用
  • 在前面添加反斜杠将其转换回数组引用

总结:在由$seq->{$label}返回的哈希中,$ARGV[4]键的值是指向数组的引用,整个过程可以按照下面的方式编写

my $ref = $seq->{$label}{$ARGV[4]};

请参考Borodin的回答,了解\@{$ref}$ref之间的区别。


你的建议与原始发布的代码不是同一件事,即访问数组的副本而不是实际引用的数组。 - Matt Jacob
1
@MattJacob: \@{$ref} == $ref。没有复制。 - Borodin
在检查 $ref 的内容时,\@{$ref} 是一种不好的方式。如果你有任何疑问,应该在使用它之前测试 ref $ref eq 'ARRAY' - Borodin

1
my $ref = \@{$seq->{$label}{$ARGV[4]}};

最好按照操作顺序从内向外工作:
  1. $ARGV[4]:通过命令行传递的第五个参数(例如:./perlscript.pl "argument1" "argument2" "argument3" "argument4" "argument5.txt"
  2. $seq->{ $label }{ $ARGV[4]}:这里保存了一个数组引用,我们知道这一点是因为当您尝试用 @{ ... } 来解引用它时,否则会收到警告信息“Not an ARRAY reference”。另外,在变量的位置上,也可以使用裸字符串(例如:$seq->{ 'some label' }{ 'some other label'}
  3. @{ $seq->{ $label }{ $ARGV[4] } }:这是进行解引用的操作,如#3所述
  4. \@{ $seq->{ $label }{ $ARGV[4] } }:反斜杠使其再次成为一个引用,澄清了哈希表中保存的是数组引用
  5. my $ref = \@{ $seq->{ $label }{ $ARGV[4] } };:标准的变量赋值

我们没有看到太多其他代码,所以很难说这需要更新多少。通常,您会希望对输入进行消毒,以确保不会传递任何坏数据或极大的数据。此外,您还需要使其更有意义。 $seq 可以表示序列或任何其他内容, $label 不太可识别,并且像您所做的任何 $ARGV 一样,通常意味着其他地方未完成某些操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接