在 Perl 中引用哈希的哈希

Deferencing hash of hashes in Perl

抱歉这么长post,对于Perl 的老手来说,代码应该很容易理解。我是 Perl 的新手,我正在尝试找出这段代码:

my %regression;

print "Reading regression dir: $opt_dir\n";

foreach my $f ( glob("$opt_dir/*.regress") ) {
    my $name = ( fileparse( $f, '\.regress' ) )[0];
    $regression{$name}{file} = $f;

    say "file $regression{$name}{file}";
    say "regression name $regression{$name}";
    say "regression name ${regression}{$name}";

    &read_regress_file( $f, $regression{$name} );
}


sub read_regress_file {
    say "args @_";

    my $file = shift;
    my $href = shift;

    say "href $href";

    open FILE, $file or die "Cannot open $file: $!\n";

    while ( <FILE> ) {
        next if /^\s*\#/ or /^\s*$/;
        chomp;

        my @tokens = split "=";
        my $key    = shift @tokens;
        $$href{$key} = join( "=", @tokens );
    }

    close FILE;
}

say 行是我添加到调试的内容。


我的困惑是子程序的最后一部分read_regress_file。看起来 href 是来自行 my $href = shift; 的引用。但是,我试图弄清楚传递的散列是如何首先被引用的。

%regression 是具有 $name 键的散列。代码读取的 .regress 文件是简单文件,包含以下形式的变量及其值:

var1=value
var2=value
...

所以它看起来像这条线

my $name = (fileparse($f,'\.regress'))[0];

正在将键创建为标量和行

$regression{$name}{file} = $f;

实际上使 $name 成为一个散列。

在我的调试行中

say "regression name $regression{$name}";

打印引用,例如

regression name HASH(0x7cd198)

但是

say "regression name ${regression}{$name}";

打印一个名字,比如

regression name {filename}

大括号内为文件名。

但是,使用

say "regression name $$regression{$name}";

不打印任何内容。

据我了解,regression 似乎是一个实际的散列,但引用是嵌套的散列,name

为什么我使用大括号的引用测试行有效,但其他形式的取消引用 ($$) 不起作用?

另外,为什么打印出来的名字还是用大括号括起来?我不应该取消引用 $name 吗?

如果这难以阅读,我很抱歉。我很困惑实际引用了哪个散列,以及如果引用是嵌套散列如何引用它们。

我的理解是这样的:

$regression{$name} 

代表一个hashref,看起来像这样:

{ file => '...something...'}

因此,为了取消引用 $regression{$name} 返回的 hashref,您必须执行以下操作:

%{ $regression{$name} }

为了得到完整的哈希。

为了得到散列的文件属性,这样做:

$regression{$name}->{file}

希望这对您有所帮助。

这是一个艰难的过程。您发现了一些非常笨拙的代码,这些代码显示了很可能是 Perl 中的错误,并且您对取消引用 Perl 数据结构感到困惑。标准的 Perl 安装包括全套文档,我建议您看一下 perldoc perlreftut,它也可以在 perldoc.com

在线获得

最明显的是您正在编写非常老式的 Perl。自从 14 年前 v5.8 发布以来,使用和号 & 调用 Perl 子例程一直不被认为是好的做法

我认为没有必要在第一个 for 循环开始时超出您明显的实验性路线。一旦你理解了这一点,剩下的就应该遵循

say "file $regression{$name}{file}";
say "regression name $regression{$name}";
say "regression name ${regression}{$name}";

首先,在字符串中扩展数据结构引用是不可靠的。 Perl 试图按照你的意思去做,但是很容易在没有意识到的情况下写出模棱两可的东西。使用 printf 通常要好得多,这样您就可以单独指定嵌入值。例如

printf "file %s\n", $regression{$name}{file};

也就是说,你有问题。 $regression{$name} 访问哈希 %regression 的元素,其键等于 $name。该值是对另一个散列的引用,因此行

say "regression name $regression{$name}";

打印类似

的东西
regression name HASH(0x29348b0)

你不想看到的

您的第一次尝试 $regression{$name}{file} 访问具有密钥 file 的辅助哈希的元素。效果不错

但是${regression}{$name}应该和$regression{$name}是一样的。在字符串外面是,但在里面就像 ${regression}{$name} 分开处理

这里真的有太多问题让我无法开始猜测你被困在哪里,尤其是在无法谈论细节的情况下。但是如果我像这样重写初始代码可能会有所帮助

my %regression;
print "Reading regression dir: $opt_dir\n";

foreach my $f ( glob("$opt_dir/*.pl") ) {

    my ($name, $path, $suffix) = fileparse($f, '\.regress');

    $regression{$name}{file} = $f;
    my $file_details = $regression{$name};

    say "file $file_details->{file}";

    read_regress_file($f, $file_details);
}

我已经将散列引用复制到 $file_details 并像那样将其传递给子例程。你能看到 %regression 的每个元素都以文件名作为键值,并且每个值都是 的引用 包含由 [= 填充的值的另一个哈希30=]?

希望对您有所帮助。这不是一个真正的语言基础教学论坛,所以我认为我不能做得更好