在Perl中引用哈希哈希

时间:2016-05-12 19:31:02

标签: perl hash nested dereference

对于这篇长篇文章感到抱歉,对于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

为什么我的deference测试行使用大括号工作,但另一种形式的解除引用($$)不起作用?

另外,为什么名字在打印时仍然被大括号包围?我不应该取消引用$name吗?

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

2 个答案:

答案 0 :(得分:2)

这是一个艰难的。您发现了一些非常笨拙的代码,它们显示了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的每个元素都被文件的名称键入,并且每个值都是的引用,这个哈希包含read_regress_file填充的值?

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

答案 1 :(得分:0)

我的理解是:

$regression{$name} 

表示hashref,如下所示:

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

因此,为了取消引用$regression{$name}返回的hashref,你必须做类似的事情:

%{ $regression{$name} }

为了获得完整的哈希值。

为了获取哈希的文件属性,请执行以下操作:

$regression{$name}->{file}

希望这有帮助。