2016-05-12 164 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