2016-05-12 113 views
1

对不起,对于这篇较长的文章,代码应该很容易理解Perl的退伍军人。我是新来的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吗?

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

+1

当您对结构有疑问时,[Data :: Dumper'](http://perldoc.perl.org /Data/Dumper.html)是_great_帮助。 尝试'使用Data :: Dumper;'然后(在'read_regress_file'中)'print Data :: Dumper-> Dump([$ href]);'。您必须传递一个引用,即'$ href'或'\%regression'。 – PerlDuck

+0

你的问题非常缺乏重点。你谈了很多关于你的困惑,但从不问一个问题。你想知道什么? – Borodin

回答

2

这是一个艰难的。你已经发现了一些非常尴尬的代码,它显示了Perl中可能存在的错误,并且你对解引用Perl数据结构感到困惑。标准的Perl安装包括一整套文档,我建议你看看perldoc perlreftut,它也可以在网上找到perldoc.com

最明显的是你正在编写非常老式的Perl。使用&符号&来调用Perl子程序从14年前发布v5.8以来一直没有被认为是很好的做法

我认为在第一个开始时没有太多需要超出您明确的实验性行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}访问其密钥等于$name的散列%regression的元素。这价值是另一个散列的引用,所以行

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填充的值的散列值?

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

+0

鲍罗廷,谢谢你的广泛答复。我应该说我并不是一个程序员,我的同事也不是。我知道TCL,而且这段代码是上周写的:) 我对此有点更清楚了。散列键值必须是标量,所以嵌套散列总是被报告为对嵌套散列的引用。这与调用它们的尴尬语法相结合(以及它们在传递给子目录时的行为方式)令人困惑,尤其是因为有3种方法可以解除引用。 'printf'也很有用;我一定会使用在调试代替 干杯! – jktstance

+0

@jktstance:它会帮助你更清楚地使用你的命名法,哈希和数组有* * *每个元素都有一个*键*(或一个*索引*)和一个标量*值*。哈希是由字符串索引的,而数组是通过非负整数索引的。我不确定'3种方式来取消引用东西'的意思吗?一个哈希引用$ href可能被解散为编写'%$ href',但更多的时候你会想要访问它的一个元素,而'$ href'引用的''key''的元素是'$ href - > {key}'。替代'$$ href {key}'是陈旧的,应该是避免 – Borodin

+0

@jktstance:通过寻求*特定*问题的帮助,您可能会得到更多有用的答案。如果没有他们,我们所能做的就是为整个情况涂一个总的评论。是“不是一个程序员太多”*你并不是真正有能力说有一种*“尴尬的语法来称呼他们”*(你并不是指**调用这里 - 这是别的althogether)。你不会因为一个你不知道的语言发现错误而不是承认这个问题真的是你自己缺乏知识 – Borodin

0

我不解的是,这样的:

$regression{$name} 

表示hashref,它看起来像这样:

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

所以,为了取消引用hashref通过$regression{$name}返回,你必须做例如:

%{ $regression{$name} } 

为了得到完整的散列。

为了获得哈希的文件属性,这样做:

$regression{$name}->{file} 

希望这有助于。

+1

,或者,在5.24.0中,无需指定特征,postfix-deref(不需要使用circumfix操作符)! '$回归{$名称} - >%*'。我仍然在围绕这个功能,但我想我只是把它扔在那里 – stevieb