Perl 哈希的創(chuàng)建和引用介紹
語(yǔ)法
創(chuàng)建'引用'僅有兩種方法,使用它也是兩種。
創(chuàng)建引用
創(chuàng)建規(guī)則 1
如果你在一個(gè)變量前加一個(gè)'/'號(hào),你就得到了這個(gè)變量的'引用'。
$aref = /@array; # $aref 保存著指向@array的'引用'
$href = /%hash; # $href 保存著指向%hash的'引用'
當(dāng)你把'引用'保存在類(lèi)似 $aref 或 $href的變量中,你就可以象操作其他標(biāo)量一樣copy或保存它。
$xy = $aref; # $xy 現(xiàn)在保存了指向 @array 的'引用'
$p[3] = $href; # $p[3] 現(xiàn)在保存了指向 %hash 的'引用'
$z = $p[3]; # $z 現(xiàn)在保存了指向 %hash 的'引用'
這些例子展示了如何創(chuàng)建命名變量的'引用',但是有時(shí)候,我們創(chuàng)建的數(shù)組或哈希沒(méi)有名字。這個(gè)和你使用沒(méi)有放到變量中去的字符串'/n'或數(shù)字'80'類(lèi)似。
創(chuàng)建規(guī)則 2
[ ITEMS ] 創(chuàng)建了一個(gè)新的、匿名的數(shù)組,并返回一個(gè)指向這個(gè)數(shù)組的'引用'。 { ITEMS } 創(chuàng)建了一個(gè)新的、匿名的哈希,并返回那個(gè)哈希的一個(gè)'引用'。
$aref = [ 1, "foo", undef, 13 ];
# $aref 保存了這個(gè)數(shù)組的'引用'
$href = { APR =>; 4, AUG =>; 8 };
# $href 保存了這個(gè)哈希的'引用'
從規(guī)則 2 中得到的'引用'和從規(guī)則 1 中得到的'引用'是同一種類(lèi)型的:
# 這里:
$aref = [ 1, 2, 3 ];
# 和上面一樣:
@array = (1, 2, 3);
$aref = /@array;
前面一種方法是后面兩行的縮寫(xiě),除了第一種方法沒(méi)有創(chuàng)建一個(gè)多余的數(shù)組變量@array。
如果你只是編寫(xiě)符號(hào) [], 你將得到一個(gè)新的、空匿名數(shù)組。如果你使用符號(hào) {},就能得到一個(gè)新的、空匿名哈希。
使用引用
當(dāng)你創(chuàng)建了一個(gè)'引用'后,你可以對(duì)它做什么操作呢?它是標(biāo)量,你可以象處理任何標(biāo)量一樣保存和取回它。除此之外,還有兩種使用方法:
使用規(guī)則 1
你可以始終用一個(gè)帶有大括號(hào)的數(shù)組'引用',來(lái)替換一個(gè)數(shù)組的名字。例如,用 @{$aref} 代替 @array。
下面是一個(gè)用法的一些例子:
數(shù)組:
@a @{$aref} 一個(gè)數(shù)組
reverse @a reverse @{$aref} 對(duì)一個(gè)數(shù)組做倒序排序
$a[3] ${$aref}[3] 數(shù)組中的一個(gè)成員
$a[3] = 17; ${$aref}[3] = 17 對(duì)一個(gè)成員賦值
上面每行中,兩個(gè)表達(dá)式實(shí)現(xiàn)的是同一種功能。左邊那個(gè)是對(duì)數(shù)組@a操作,右邊那個(gè)是對(duì)'引用'$aref所指向的數(shù)組操作。它們對(duì)數(shù)組產(chǎn)生相同的作用。
使用哈希的'引用'和數(shù)組的'引用'完全一樣。
%h %{$href} 一個(gè)哈希
keys %h keys %{$href} 從哈希中將鍵取出來(lái)
$h{'red'} ${$href}{'red'} 哈希中的一個(gè)成員
$h{'red'} = 17 ${$href}{'red'} = 17 對(duì)一個(gè)成員賦值
你對(duì)一個(gè)'引用'無(wú)論想做什么,使用規(guī)則 1 已經(jīng)告訴你怎么做了。 你只要象使用常規(guī)的數(shù)組或哈希一樣編寫(xiě)Perl代碼,然后把數(shù)組或哈希的名字用 {$reference}來(lái)替代?!?dāng)我只有一個(gè)'引用'時(shí),怎么來(lái)遍歷整個(gè)數(shù)組?'你這樣寫(xiě):
for my $element (@array) {
...
}
接著用'引用'替代數(shù)組名@array:
for my $element (@{$aref}) {
...
}
‘怎當(dāng)我只有一個(gè)'引用'時(shí),怎么來(lái)打印一個(gè)哈希的內(nèi)容?'先寫(xiě)一個(gè)打印整個(gè)哈希的代碼:
for my $key (keys %hash) {
print "$key =>; $hash{$key}/n";
}
然后用'引用'代替那個(gè)哈希的名字:
for my $key (keys %{$href}) {
print "$key =>; ${$href}{$key}/n";
}
使用規(guī)則 2
使用規(guī)則 1 是你真正需要的,因?yàn)樗嬖V了你怎么來(lái)處理一個(gè)'引用',而它對(duì)幾乎任何的'引用'都有效。但是我們通常做的事情只是和數(shù)組或哈希中的一個(gè)成員有關(guān),使用規(guī)則 1 卻是很笨重的方法,所以還有簡(jiǎn)單的方法。
${$aref}[3] 太難閱讀,所以我們這樣寫(xiě) $aref->[3]。
${$href}{red} 寫(xiě)的太笨重, 所以我們這樣寫(xiě) $href->{red}。
如果 $aref 保存的是一個(gè)數(shù)組的'引用',那么 $aref->[3] 就是這個(gè)數(shù)組的第四個(gè)成員。不要和 $aref[3] 相混淆,這個(gè)代表的是一個(gè)完全不同的數(shù)組的第四個(gè)成員,這個(gè)迷惑的數(shù)組是@aref。 變量 $aref 和 @aref 是完全不相關(guān)的,就像 $item 和 @item 一樣。
同樣的, $href->{'red'} 是哈希'引用' 的變量$href的一部分,甚至這是一個(gè)沒(méi)有名字的哈希。而$href{'red'} 是另一個(gè)容易混淆的命名哈希 %href 的一部分。很容易忘記寫(xiě)上符號(hào)' ->',如果出現(xiàn)這種情況,當(dāng)你的程序從一個(gè)你不想取數(shù)據(jù)的數(shù)組和哈希中取出了成員,你會(huì)得到奇怪的計(jì)算結(jié)果。
例子
讓我們來(lái)看一個(gè)例子:
首先,記住 [1, 2, 3] 創(chuàng)建了一個(gè)匿名數(shù)組,包含了 (1, 2, 3),然后返回一個(gè)數(shù)組的'引用'。
現(xiàn)在想一下:
@a = ( [1, 2, 3],
[4, 5, 6],
[7, 8, 9]
);
@a 是一個(gè)擁有三個(gè)成員的數(shù)組,每一個(gè)成員是另一個(gè)數(shù)組的'引用'。
$a[1] 是其中的一個(gè)'引用'。它指向一個(gè)數(shù)組,這個(gè)數(shù)組包含了(4, 5, 6),因?yàn)檫@是一個(gè)數(shù)組的'引用',使用規(guī)則 2 告訴我們可以這樣寫(xiě) $a[1]->[2],用來(lái)取得這個(gè)數(shù)組的第三個(gè)成員。 $a[1]->[2] 值是6。 同樣的,$a[0]->[1] 值是 2。這里我們就像在使用一個(gè)二維數(shù)組;你可以是用 $a[ROW]->[COLUMN] 來(lái)取得或設(shè)置數(shù)組中任何一行任何一列中的成員。
這些符號(hào)看起來(lái)還是有些麻煩,所以還有更加簡(jiǎn)單的用法:
箭頭符號(hào)規(guī)則
在兩個(gè)下標(biāo)之間的箭頭是可選的。
我們可以用這個(gè)寫(xiě)法$a[1][2]來(lái)代替$a[1]->[2];它們是相同的。相對(duì)于$a[0]->[1] = 23,我們這樣寫(xiě)$a[0][1] = 23;它們也是相同的。
現(xiàn)在它們看起來(lái)真的象二維數(shù)組了!
你可以發(fā)現(xiàn)為什么箭頭這么重要。沒(méi)有它們,我們必須這樣寫(xiě)${$a[1]}[2],而不是$a[1][2]。對(duì)于三維數(shù)組,它們使我們可以簡(jiǎn)單地寫(xiě)成$x[2][3][5]而不是寫(xiě)成難讀的${${$x[2]}[3]}[5]方式。
解決辦法
下面是前面提出來(lái)的問(wèn)題的解決方法,就是關(guān)于城市和國(guó)家名稱(chēng)的重新格式化。
my %table;
while (<>) {
chomp;
my ($city, $country) = split /, /;
$table{$country} = [] unless exists $table{$country};
push @{$table{$country}}, $city;
}
foreach $country (sort keys %table) {
print "$country: ";
my @cities = @{$table{$country}};
print join ', ', sort @cities;
print "./n";
}
這個(gè)程序分成兩部分: 第 2--7 行完成數(shù)據(jù)的輸入和數(shù)據(jù)結(jié)構(gòu)的創(chuàng)建。 第 8-13 行分析這個(gè)數(shù)據(jù)并打印報(bào)告。我們?cè)O(shè)置了一個(gè)哈希 %table,它的鍵是國(guó)家名稱(chēng),它的健值是這個(gè)國(guó)家名稱(chēng)對(duì)應(yīng)的城市名的數(shù)組的'引用'。這個(gè)數(shù)據(jù)結(jié)構(gòu)看起來(lái)如下:
%table
+-------+---+
| | | +-----------+--------+
|Germany| *---->| Frankfurt | Berlin |
| | | +-----------+--------+
+-------+---+
| | | +----------+
|Finland| *---->| Helsinki |
| | | +----------+
+-------+---+
| | | +---------+------------+----------+
| USA | *---->| Chicago | Washington | New York |
| | | +---------+------------+----------+
+-------+---+
我們先來(lái)分析輸出部分。假設(shè)我們已經(jīng)擁有了這個(gè)結(jié)構(gòu),那么我們?cè)趺磥?lái)輸出呢?
foreach $country (sort keys %table) {
print "$country: ";
my @cities = @{$table{$country}};
print join ', ', sort @cities;
print "./n";
}
%table是一個(gè)普通的哈希,我們從它這里可以取得一列鍵,對(duì)鍵進(jìn)行排序,并遍歷所有的鍵。這里唯一使用'引用'的是第10行。$table{$country} 查看了哈希中的鍵$country并取得它的值。這個(gè)健值是對(duì)應(yīng)國(guó)家中的城市數(shù)組的'引用'。 使用規(guī)則 1 告訴我們可以通過(guò)使用 @{$table{$country}}來(lái)恢復(fù)整個(gè)數(shù)組。第10行就象
@cities = @array;
不同的是這里的數(shù)組的名字被'引用' {$table{$country}}所替代。符號(hào) @ 告訴Perl去獲取整個(gè)數(shù)組。得到了城市的列表后,我們照樣對(duì)其進(jìn)行排序,合并城市名,并打印出來(lái)。
第2-7行負(fù)責(zé)創(chuàng)建數(shù)據(jù)結(jié)構(gòu),如下:
while (<>) {
chomp;
my ($city, $country) = split /, /;
$table{$country} = [] unless exists $table{$country};
push @{$table{$country}}, $city;
}
第 2-4 行獲取城市和國(guó)家的名稱(chēng)。第5行查看這個(gè)國(guó)家名稱(chēng)是不是已經(jīng)作為一個(gè)鍵存放在哈希里面了,如果沒(méi)有,程序就使用符號(hào)[] (創(chuàng)建規(guī)則 2)創(chuàng)建一個(gè)新的、空的匿名數(shù)組,同時(shí)把一個(gè)指向這個(gè)匿名數(shù)組的'引用'作為健值放到哈希里面去了。
第6行將城市名放到對(duì)應(yīng)的數(shù)組里面。$table{$country} 現(xiàn)在保存了一個(gè)'引用',它指向所對(duì)應(yīng)的國(guó)家的城市的數(shù)組。第6行就象
push @array, $city;
不同的是這里的數(shù)組名被{$table{$country}}所替代。 命令 push 將城市名加到這個(gè)'引用'指向數(shù)組的最后。
這里有一個(gè)要點(diǎn)被我忽略了。第5行是不需要的。我們可以取掉它。
while (<>) {
chomp;
my ($city, $country) = split /, /;
#### $table{$country} = [] unless exists $table{$country};
push @{$table{$country}}, $city;
}
如果在哈希 %table 中已經(jīng)有這個(gè)國(guó)家名 $country的記錄,那么,加不加第5行沒(méi)有任何區(qū)別。第6行會(huì)自己定位到$table{$country}這個(gè)'引用'指向的數(shù)組,把值 $city 放到數(shù)組中去。但是如果在%table中沒(méi)有那個(gè)鍵,比如Greece,那么它會(huì)怎么辦呢?
這是Perl,它會(huì)自己準(zhǔn)確地完成工作。你想把一個(gè)Athens賦值給一個(gè)不存在地?cái)?shù)組,那么Perl會(huì)幫助你創(chuàng)建一個(gè)新的、空的匿名數(shù)組,將它放到哈希%table里面去,然后把值 Athens 放到這個(gè)數(shù)組中。這個(gè)被稱(chēng)為'自動(dòng)生成' --讓事物自己自動(dòng)產(chǎn)生出來(lái)。 Perl 發(fā)現(xiàn)在哈希里面沒(méi)有這個(gè)鍵,就自動(dòng)地創(chuàng)建了一個(gè)新的哈希記錄。 Perl 發(fā)現(xiàn)你想要使用數(shù)組作為哈希的健值,它就自動(dòng)創(chuàng)建一個(gè)匿名的空數(shù)組,并將指向這個(gè)數(shù)組的'引用'放到那個(gè)哈希中去。一般, Perl 創(chuàng)建的數(shù)組只有一個(gè)成員大小,用于保存這個(gè)新的城市名。
其他集錦
我承諾以10%的細(xì)節(jié)來(lái)使你得到90%的好處,那就意味著我跳過(guò)了90%的知識(shí)的細(xì)節(jié)?,F(xiàn)在來(lái)看一下其中的重要的部分,這個(gè)比閱讀手冊(cè) the perlref manpage 要容易得多,手冊(cè)討論了100%的細(xì)節(jié)。
手冊(cè) the perlref manpage中的一些集錦:
你可以對(duì)任何東西創(chuàng)建'引用',包括標(biāo)量,函數(shù)和其他的引用。
在 使用規(guī)則 1 中,當(dāng)大括號(hào)里面是一個(gè)象$aref這樣的標(biāo)量變量時(shí),你可以省略掉這個(gè)大括號(hào)。例如, @$aref 和 @{$aref}是一樣的,$$aref[1] 和 ${$aref}[1]是一樣的。 如果你是初學(xué)者,建議你還是養(yǎng)成加上大括號(hào)的習(xí)慣。
下面的操作不會(huì)copy '引用'指向的數(shù)組:
$aref2 = $aref1;
你將得到兩個(gè)'引用',它們都指向同一個(gè)數(shù)組。如果你修改了$aref1->[23]的值,那么你查看變量$aref2->[23]時(shí),它也相應(yīng)地變了。
要copy這個(gè)數(shù)組,你需要這樣
$aref2 = [@{$aref1}];
使用符號(hào) [...] 來(lái)創(chuàng)建一個(gè)新的匿名數(shù)組, 而且這個(gè)新的數(shù)組的'引用'被賦值給了$aref2 。 這個(gè)新的數(shù)組用'引用'$aref1所指向的數(shù)組的內(nèi)容來(lái)初始化。
同樣的,要copy一個(gè)匿名哈希,你需要這樣
$href2 = {%{$href1}};
如果要判斷一個(gè)變量保存的內(nèi)容是不是'引用',使用函數(shù)ref 。如果它的參數(shù)是'引用',返回的值是'真'。實(shí)際上,它做得更好:如果是一個(gè)哈希的引用,它返回'HASH',如果是一個(gè)數(shù)組的引用,那么就返回'ARRAY'。
如果你想像字符串一樣使用'引用'的話,你得到的字符串就像
ARRAY(0x80f5dec) or HASH(0x826afc0)
如果看到一個(gè)像這樣的字符串,你應(yīng)該知道你錯(cuò)誤地輸出了一個(gè)'引用'。
這種顯示方式的另一個(gè)作用是你可以用eq來(lái)比較兩個(gè)'引用',看它們是不是指向相同的東西。(你通??梢允褂?== 來(lái)比較,因?yàn)樗鼤?huì))
你可以像使用'引用'一樣來(lái)使用一個(gè)字符串。如果你使用"foo"作為一個(gè)數(shù)組的'引用',它就是指向數(shù)組 @foo的一個(gè)引用。這被稱(chēng)為'軟引用'或‘符號(hào)引用 '。 使用申明 use strict 'refs' 可以取消這個(gè)功能,如果你不小心使用了它,會(huì)導(dǎo)致各種可能的錯(cuò)誤。
你可能更喜歡查看 the perllol manpage,而不是手冊(cè) the perlref manpage;它詳細(xì)地討論了列表的列表和多緯數(shù)組。然后,你可以繼續(xù)學(xué)習(xí)手冊(cè) the perldsc manpage;它是數(shù)據(jù)結(jié)構(gòu)的Cookbook, 它提供了處理哈希的數(shù)組,數(shù)組的哈希,以及其他數(shù)據(jù)結(jié)構(gòu)的方法。
相關(guān)文章
Perl實(shí)現(xiàn)高水線算法(解決多值比較問(wèn)題方法)
這篇文章主要介紹了Perl實(shí)現(xiàn)高水線算法(解決多值比較問(wèn)題方法),從本文代碼示例中還可以學(xué)習(xí)到數(shù)組遍歷、函數(shù)寫(xiě)法、函數(shù)調(diào)用等知識(shí),需要的朋友可以參考下2015-06-06Perl中的控制結(jié)構(gòu)學(xué)習(xí)筆記
這篇文章主要介紹了Perl中的控制結(jié)構(gòu)學(xué)習(xí)筆記,本文講解了條件判斷、循環(huán)語(yǔ)句、單行條件等內(nèi)容,需要的朋友可以參考下2015-02-02perl的格式化(Format)報(bào)表輸出實(shí)現(xiàn)代碼
perl有最好的文本數(shù)據(jù)處理能力.這是大家都知道的.在perl本身有一個(gè)別的軟件沒(méi)有的小功能,就是Perl格式.它相當(dāng)于簡(jiǎn)單的命令行報(bào)表和圖表輸出2013-01-01Perl localtime時(shí)間函數(shù)的應(yīng)用介紹
Perl時(shí)間函數(shù)localtime的使用介紹,這里簡(jiǎn)單的介紹下,更多請(qǐng)查看官方介紹2013-02-02