table of contents
PERLDATA(7) | Perl Programmers Reference Guide | PERLDATA(7) |
NAME¶
perldata- Perl 資料型別
DESCRIPTION 描述¶
Variable names 變數名¶
Perl 有三種內建的資料型別:標量,陣列和關聯陣列(即“雜湊表, hash”)。陣列以數字為索引,通常以0開始,升序排列。雜湊表以與值相關聯 的字串為索引,內部排列是無序的。
值通常透過一個變數名(或變數名的引用)來引用。變數名的字首字元顯示了值的 資料型別。其餘部分指明瞭引用的是哪一個特定的值。通常變數名是一個唯一的標 識符,以字母或下劃線開始,包括字母、下劃線和數字。某些情況下,也可以是以 `::' 分隔的一串識別符號(或者是過時的`'');除了最後一 個,其它都是包名,用來定位最後一個識別符號所在的位置(詳情參見 perlmod 中的 Packages)。可以用一個簡單的識別符號來替代它,利用引用就可以。下文有詳述, 也可參見 perlref .
Perl 也有內建的變數,其名稱不遵循這一規則。它們名稱古怪,這樣可以避免與你的變數名衝突。模式匹配中被匹配到的字串是以`$' 加一個數字的變數名來存放的(參見 the perlop manpage 和 the perlre manpage)。 另外,還有幾個使你可以介入perl 內部工作的特殊變數,其名稱中包含標點和控制字元(參見 perlvar )
標量以 '$'開始, 即使它是陣列或雜湊的元素也是如此。可以把 '$' 理解為`s' ,表示scalar(標量)。(譯者注:此處根據有關文件,做了改動,下面的@處也 是這樣)
$days # 簡單標量 "days" $days[28] # 陣列 @days的第29個元素 $days{'Feb'} # 雜湊 %days的 `Feb' 所對應的值 $#days # 陣列 @days的最後一個元素的索引值
整個陣列(或陣列和雜湊的區域性)以 '@'開始, 它類似英文中的“these” 或“those” (這些...那些...),表示期望有多個值。
@days # ($days[0], $days[1],... $days[n]) @days[3,4,5] # 即 ($days[3],$days[4],$days[5]) @days{'a','c'} # 即 ($days{'a'},$days{'c'})
整個雜湊以 '%' 開始:
%days # (key1, val1, key2, val2 ...)
另外,子程式以'&'來表示, 但有時在不引起誤解的情況下也可以不用, 就象 “do” 在英語中常常省略一樣。 符號表項以 '*' 作為開始字元, 不過你 現在還不用關心這個 (if ever ;-)
每一種資料型別都有它自己的名字空間,常量識別符號也一樣。這意味著你可以使用 同一個名字來命名標量、陣列、雜湊、檔案控制代碼、目錄控制代碼、子程式、格式或標籤。 即$foo 和@foo 是不同的變數。也即意味著$foo[1] 是 @foo 的一部分, 而不是$foo的一部分. 這看來有些怪異,不過很 正常,因為它本來就怪異。
因為變數名以 '$', '@', 或 '%'開始, 保留詞對變數沒有什麼影響。保留詞影響 的是標籤和檔案控制代碼,因為它們不是以特殊字元字首開始的。你不能用“log” 來命名檔案控制代碼,因為它是保留詞(提示:你可以用 `open(LOG,'logfile')' 而不是 `open(log,'logfile')'). 使用大寫的檔案控制代碼既增加了可讀性, 又減少了衝突的發生。大小寫是有意義的--“FOO”,“Foo”, 和“foo” 是不同的名稱。以字母或下劃線開始的名稱可以包含數字和下劃線。
可以用一個返回相關引用的表示式來替換這樣的變數名。參見 perlref
以數字開始的變數名只能包含數字。不是以字母、下劃線或數字開始的變數名只能 含有一個字元,如:$% 或$$. (大部分這樣的變數都有特殊的意 義。例如,$$ 是當前程序的id。)
Context 上下文¶
在 Perl 中有時操作或值的意義取決於該操作或值所處的上下文。有兩個主要的上 下文:列表和標量上下文。相當一部分操作在需要列表的上下文中返回列表,在需 要標量的上下文中返回標量。這在有關該操作的文件中會提到。換句話講,Perl會 過載這些運算子。英語中的某些詞,如`fish'和`sheep'與此類似。
操作可以根據不同的上下文返回不同的值。例如,如果這樣寫:
int( <STDIN> )
integer 操作提供標量上下文給 <> 運算子, <> 會從STDIN 讀入一行返回給 integer 操作,然後它返回其中的整型量。但如果你這樣寫:
sort( <STDIN> )
sort操作提供列表上下文給<>, <>會讀入STDIN中的每一行直到結束,然後將其傳遞給sort,sort然後將其排序輸出。
賦值比較特殊,左側的引數決定了右側的引數的上下文。賦值給標量,則右側引數的上下文是標量上下文;賦值給陣列或雜湊,則右側引數的上下文是列表上下文。賦值給列表(或片段,其實也是列表),右側的上下文也是列表上下文。
當你使用`use warnings' 編譯指示或 Perl 的-w 引數時, 你可能會看到這樣的警告:在“無效的上下文,void context” 中使用了常量 或函式。無效上下文的意思是值被丟棄不用,比如只包含有"fred"; 的語句; 或是`getpwuid(0);';. 在要求列表上下文的函式 被標量上下文環境呼叫時,也會出現這個警告.
使用者定義的子程式可能會需要檢視上下文是無效,標量,還是列表。不過,大多數並 不需要這麼做。因為標量和列表會自動插入到一個列表中。參見 perlfunc 中的 “wantarray” 以瞭解如何辨明你的函式呼叫時的上下文。
Scalar values 標量¶
Perl 中的所有資料都是標量, 標量的陣列,標量的雜湊. 標量可以是三種不同的值: 數字, 字元(串), 引用. 通常, 不同值之間的轉換是透明的. 雖然一個標量不可能有多個值, 但是它可以是一個包含多個值的陣列或雜湊的引用.
標量不一定非此即彼. 不需要宣告變數的型別是"字串","數字","引用"或其它什麼. 因為標量會自動轉換, 所以其型別不用關心. Perl 是上下文多形語言,它的標量可以是字串,數字或引用(包括物件). 其中字串和數字在大多數情況下並沒有什麼不同, 引用是強化的,不可變的帶有內建引用計數和析構器的指標.
標量在不是空字串和數字0的時候被解釋為真 TRUE. 布林上下文是這樣一種上下文, 這時不會發生數字或字串的自動轉換.
有兩種空字串(有時以"empty"表示), 定義了的和未定義的. 定義了的空字串就是長度為零的字串,如"". 未定義的空字串是一個值,這個值表示某事物並沒有真實值與它對應, 比如出錯, 或到達檔案尾, 或者你引用一個未定義的陣列或雜湊的元素時,都會返回一個未定義的空字串. 雖然在早期Perl 中,在要求已定義變數的上下文中使用未定義的變數可以使得該變數得到定義, 現在卻只有在特殊的情況下才會出現這種結果,參見the perlref manpage. 可以用defined() 函式來檢測標量是否已經定義(對陣列和雜湊無效),也可以用undef() 去除對變數的定義.
要弄清楚一個字串是否是有效的非0數字,只要看它是不是數字0和字母“0” 就足夠了(不過這在使用-w引數時,會顯示警告). 因為非數字的字串被看作0, 與awk中相似:
if ($str == 0 && $str ne "0") { warn "That doesn't look like a number"; }
這種方法可能是最好的,因為如若不然你不會正確對待IEEE 的註釋,比如`NaN' 和無窮大. 別的時候, 你可能更願意用POSIX::strtod() 函式或是正則表示式來檢測字串是否能用做數字(參見perlre).
warn "has nondigits" if /\D/; warn "not a natural number" unless /^\d+$/; # rejects -3 warn "not an integer" unless /^-?\d+$/; # rejects +3 warn "not an integer" unless /^[+-]?\d+$/; warn "not a decimal number" unless /^-?\d+\.?\d*$/; # rejects .2 warn "not a decimal number" unless /^-?(?:\d+(?:\.\d*)?|\.\d+)$/; warn "not a C float" unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
陣列的長度是標量. 透過$#days你可以知道@days的長度. 技術上講,這不是陣列的長度; 而是最後一個元素的下標,因為第一個元素的下標是0. 對$#days 賦值會改變陣列的長度. 以這種方式減少陣列的話, 會破壞其中的值, 再增加其長度也不能恢復. (Perl 4中是可以的, 我們改變了它以確保析構器被及時呼叫.)
你可以使用一些小技巧來預擴充套件一個數組(如果你知道它將會變得很大的話). 可以用給超出陣列範圍的元素賦值的方法擴充套件陣列. 可以給陣列賦值一個空列表以清空陣列. 下面語句等價:
@whatever = (); $#whatever = -1;
陣列處於標量上下文中時, 返回值是陣列的長度. (列表在標量上下文中,返回值是列表的最後一個元素,像是C中的逗號運算子, 而內建函式的返回值由它們自己決定.) 以下語句為真:
scalar(@whatever) == $#whatever - $[ + 1;
Perl 5 改變了$[ 的意義: 不必擔心別的程式改變了$[ 的值. (換言之,不推薦使用$[ ) 所以,可以寫成這樣:
scalar(@whatever) == $#whatever + 1;
有些程式設計師為了明確起見, 會使用顯式的轉換:
$element_count = scalar(@whatever);
當雜湊處於標量上下文中時, 如果雜湊為空, 返回值為假, 如果非空, 返回值為真; 說得更精確些, 返回值是個字串, 由已經使用的儲存段和分配的全部儲存段組成,二者之間以斜槓分隔. 這可以用來反映Perl的雜湊演算法的好壞. 例如, 你的雜湊中有10,000個元素,但是%HASH 的標量值為"1/16", 則說明僅用到了16個儲存段中的一個, 也許10,000個元素都在這一個儲存段中. 最好不要發生這種情況.
你可以預先為雜湊分配空間, 這要使用給keys() 函式賦值的方法來實現. 實際分配的空間是大於所給值的二的冪:
keys(%users) = 1000; # 分配 1024 空間
Scalar value constructors 標量資料構造¶
數值常量有以下浮點和整數格式:
12345 12345.67 .23E-10 # a very small number 3.14_15_92 # a very important number 4_294_967_296 # underscore for legibility 0xff # hex 0xdead_beef # more hex 0377 # octal 0b011011 # binary
在數字常量中可以在數字間插入下劃線來增加可讀性。例如,可以三位一組 (Unix 樣式的分組,例如 0b110_110_100),或者四位一組 (來表示 nibbles,例如 0b1010_0110),或者其他分組。
字串通常以單引號或雙引號括起. 與標準Unix shells中的引號相似: 雙引號可以接收轉義和變數; 單引號不可以 (除了`\'' 和`\\')). C 樣式的跳脫字元可以用來輸入新行,跳格等字元,跳脫字元的列表可以參見 perlop 中的“Quote and Quote-like Operators”
十六進位制,八進位制,或二進位制以字串形式表示(如:'0xff'),不能自動轉換為十進位制形式. hex() 和 oct() 函式可以實現轉換. 參見 perlfunc 中的 hex 和 oct 瞭解詳情.
可以在字串中直接加入新行. 字串中的變數只能是標量,陣列和陣列或雜湊的片段 (換言之, 以$或@開始, 後跟下標.). 以下語句列印``The price is $100.''
$Price = '$100'; # not interpolated print "The price is $Price.\n"; # interpolated
perl 中沒有 double interpolation,因此$100 保持不變。
正如在有些shell中一樣, 你可以用花括號括起變數名, 以便區分變數名和其後的字母及下劃線. 如果要將一個變數改寫為字串時,必須這樣做,以避免與後面的雙冒號或單引號連線起來,否則會被當作包名:
$who = "Larry"; print PASSWD "${who}::0:0:Superuser:/:/bin/perl\n"; print "We use ${who}speak when ${who}'s here.\n";
如果沒有花括號, Perl會尋找 $whospeak, $who::0, 和 $who's 變數. 後兩個是不存在的 who 包中的$0 和 $s.
實際上, 花括號中的識別符號必須是字串, 雜湊的下標也必須是字串. 都不需要引號, 前面的例子$days{'Feb'} 可以寫作 $days{Feb} 引號會自動加上. 但是下標中的其它複雜內容被解釋為表示式.
Version Strings
注意: Version Strings (v-strings) have been deprecated. They will not be available after Perl 5.8. The marginal benefits of v-strings were greatly outweighed by the potential for Surprise and Confusion.
類似`v1.20.300.4000' 這樣的形式被解釋為一個字串. 這種形式稱為 v-strings,提供了更易讀的方法來構造字串,比起"\x{1}\x{14}\x{12c}\x{fa0}" 更加易讀. 這在表示 Unicode 字串時很有用, 在使用字串比較命令(`cmp',`gt',`lt' 等)比較版本號時也非常有用. 如果其中的點號多於兩個, 則開始的`v' 可以省略.
print v9786; # prints UTF-8 encoded SMILEY, "\x{263a}" print v102.111.111; # prints "foo" print 102.111.111; # same
這種形式可以用於require 和 use 中作版本檢查.“$^V” 特殊變數中的Perl版本號就是以這種形式儲存的. 參見 perlvar 中的“$^V” 注意使用 v-strings 來儲存 IPv4 地址是不可移植的,除非同時使用 Socket 包的inet_aton()/inet_ntoa() 函式。
注意從 Perl 5.8.1 開始單個數字的 v-strings (類似`v65') 如果在`=>' 運算子(通常用來從 hash 值中區分開 hash 鍵) 之前,不是一個 v-strings,而是解釋為字串 ('v65')。在 Perl 5.6.0 到 Perl 5.8.0 它一直是 v-strings,但是這樣帶來了更多混淆和錯誤而不是優點。多個數字的 v-strings,類似`v65.66' 和65.66.67,繼續總是被當作 v-strings
特殊常量
特殊變數 __FILE__, __LINE__, 和 __PACKAGE__ 代表當前檔名,行號,和包名. 它們只能作為單獨的符號來使用; 不能用於字串中內插. 如果沒有當前包(用`package;' 指令來實現), 則__PACKAGE__ 是一個未定義的值.
控制字元 ^D 和 ^Z, 以及 __END__ 和 __DATA__ 變數可以表示檔案的邏輯結束. 其後的文字被忽略.
__DATA__ 之後的文字可以透過檔案控制代碼`PACKNAME::DATA' 讀取,`PACKNAME' 是 __DATA__ 所在的包的名稱. 控制代碼指向__DATA__ 後面的文字. 讀取結束程式會自動關閉該控制代碼`close DATA'. 為了與 __DATA__ 還沒有出現以前已經存在的程式相容, __END__ 在頂級指令碼中與 __DATA__ 性質相同(在用`require' 或`do' 呼叫時是不同的) 不過可以透過`main::DATA' 來呼叫其中的內容.
參見 SelfLoader 詳細瞭解 __DATA__, 其中還有例子. 要注意在BEGIN 塊中無法讀取DATA控制代碼: 因為BEGIN 塊在編譯時即被執行, 而此時 __DATA__ (或 __END__) 還未被程式看到.
裸詞
在文法上沒有特殊意義的詞語都被看作字串. 稱之為 "裸詞". 和檔案控制代碼以及標籤一樣, 僅包含小寫字母的裸詞有可能在將來與程式中的保留詞發生衝突, 實際上,當你使用`use warnings' 語句,或是-w 選項時, Perl會對此提出警告. 一些人可能希望完全禁止這樣的詞. 如果有如下語句:
use strict 'subs';
那麼不能被解釋為子程式的裸詞會引起編譯時錯誤. 這種限制到塊結束時終止. 而內部的塊可以撤消這一限制, 用`no strict 'subs''
數組合並分隔符
陣列和序列被合併為雙引號引用的字串時,以變數$" 指定的值 (如果指定了“use English;” 那麼是$LIST_SEPARATOR 的值) 作為分隔符,預設是空格。下列語句等價:
$temp = join($", @ARGV); system "echo $temp";
system "echo @ARGV";
在搜尋模式中(在雙引號字串中也是)有一個易混淆之處:`/$foo[bar]/' 應該是`/${foo}[bar]/' (`[bar]' 是正則表示式的字元類) 還是`/${foo[bar]}/'/ (`[bar]' 是陣列@foo 的下標) 呢? 如果@foo 不存在, 那很明顯它應該是字元類. 如果@foo 存在, Perl 會盡力猜測`[bar]' 的含義, 且它幾乎總是對的. 如果它猜錯了, 或者你比較偏執, 你可以使用花括號.
here-document 的語法已經被移動到 perlop 中的“Quote and Quote-like Operators”
List value constructors 列表值構造¶
列表是用逗號分開的各個值組成的(如果優先順序需要的話,外面還要用圓括號包圍):
(LIST)
在不需要列表的上下文中, 列表的值是最後一個元素的值, 這與C中的逗號運算子類似. 例如:
@foo = ('cc', '-E', $bar);
將列表賦給陣列@foo, 但是
$foo = ('cc', '-E', $bar);
將$bar 的值賦給$foo. 注意, 陣列在標量上下文中的值是陣列的長度; 下例將3賦給$foo:
@foo = ('cc', '-E', $bar); $foo = @foo; # $foo gets 3
列表的最後可以輸入逗號, 所以這樣也是正確的:
@foo = ( 1, 2, 3, );
要將here-document 賦給陣列, 一行作為一個元素, 可以這樣作:
@sauces = <<End_Lines =~ m/(\S.*\S)/g; normal tomato spicy tomato green chile pesto white wine End_Lines
列表會自動插入子列表. 也即, 下例將展開陣列,雜湊等, 並將其中的每一個元素作為該新列表的一個元素. 陣列或雜湊失去其原來的身份.列表
(@foo,@bar,&SomeSub,%glarch)
包括@foo,@bar的每一個元素,包括函式 SomeSub 返回值列表的每一個元素, 包括 %glarch 的每一個字值對. 要想使用不內插的列表, 可以參見 perlref
空列表可以表示為(). 在列表中插入空列表沒有意義. ((),(),()) 與()相同. 同樣, 內插一個空陣列也沒有意義.
合併的語法表示開和閉括號都是可選的 (除非為表示優先順序需要);而列表可以以可選的逗號結束表示列表中的多個逗號是合法的語法。列表`1,,3' 是兩個列表的並置,`1,' 還有3, 第一個以可選的逗號結束。`1,,3' 是`(1,),(3)' 也是`1,3' (類似的,`1,,,3' 是`(1,),(,),3' 也是`1,3' 等等) 不過我們不建議你使用這麼混亂的寫法
列表也可以象陣列一樣使用下標. 為了避免歧義需要在列表外使用括號. 例如:
# Stat returns list value. $time = (stat($file))[8];
# SYNTAX ERROR HERE. $time = stat($file)[8]; # OOPS, FORGOT PARENTHESES
# Find a hex digit. $hexdigit = ('a','b','c','d','e','f')[$digit-10];
# A "reverse comma operator". return (pop(@foo),pop(@foo))[0];
可以給列表賦值, 當然列表中的每個元素必須合法才行:
($a, $b, $c) = (1, 2, 3);
($map{'red'}, $map{'blue'}, $map{'green'}) = (0x00f, 0x0f0, 0xf00);
特例是可以賦值為`undef'。當忽略程式的某些返回值時這很有用:
($dev, $ino, undef, undef, $uid, $gid) = stat($file);
列表賦值處於標量上下文中時, 返回值是等號右側的表示式的元素個數:
$x = (($foo,$bar) = (3,2,1)); # set $x to 3, not 2 $x = (($foo,$bar) = f()); # set $x to f()'s return count
這在布林上下文中很方便, 因為多數列表函式在結束時返回空列表, 這時列表賦值會返回0, 被解釋為FALSE.
它也是一個有用的習慣的來源,就是在列表上下文中執行一個函式或操作,然後記錄返回值的個數,方法是為一個空列表賦值,然後在標量上下文中使用這個值。例如,如下程式碼:
$count = () = $string =~ /\d+/g;
將置$count 為$string 中找到的數字組數量。這樣能行的原因是模式匹配是列表上下文 (因為它被賦予一個空列表),因此返回所有匹配部分的列表。在標量上下文中的列表賦值將它轉換為元素的個數 (這裡是模式被匹配的數量),然後賦值給$count。注意簡單地使用
$count = $string =~ /\d+/g;
沒有作用,因為在標量上下文中的模式匹配只會返回 true 或 false,而不是所有的匹配。
最後一個元素可以是陣列或雜湊:
($a, $b, @rest) = split; my($a, $b, %rest) = @_;
當然可以在任何位置使用陣列或雜湊, 不過第一個陣列或雜湊會將所有的值都據為己有, 其它的元素都會變為undefined.這在my() 或 local()中或許有用.
雜湊可以用含有字值對的列表來初始化:
# same as map assignment above %map = ('red',0x00f,'blue',0x0f0,'green',0xf00);
列表和陣列互動性很強, 雜湊則不然. 你可以象使用陣列時一樣對列表使用下標並不意味著可以象使用雜湊一樣使用列表. 同樣,處於列表中的雜湊總是以字值對的形式展開. 因此有時使用引用要更好一些.
通常在字值對中使用`=>' 運算子會更易讀.`=>' 與逗號作用相同, 不過它 還有一個作用, 那就是可以使它左側的物件被解釋為字串: 如果該物件是裸 字的話,將是合法的識別符號 (`=>' 不引用包含雙冒號的複合識別符號). 這在初始 化雜湊時棒極了:
%map = ( red => 0x00f, blue => 0x0f0, green => 0xf00, );
或者初始化雜湊的引用:
$rec = { witch => 'Mable the Merciless', cat => 'Fluffy the Ferocious', date => '10/31/1776', };
or for using call-by-named-parameter to complicated functions:
$field = $query->radio_group( name => 'group_name', values => ['eenie','meenie','minie'], default => 'meenie', linebreak => 'true', labels =>\%labels );
注意雜湊初始化時的順序和輸出時的順序並不一定相同. 要得到順序的輸出可以參見 perlfunc 中的“sort”
Subscripts 下標¶
陣列可以用一個美元符號,加上它的名字(不包括前導的`@'),加上方括號和其中包含的下標來取得值。例如:
@myarray = (5, 50, 500, 5000); print "Element Number 2 is", $myarray[2], "\n";
陣列下標從 0 開始。負值下標返回從尾部開始數的值。在我們的例子中,$myarray[-1] 將是 5000,$myarray[-2] 是 500。
Hash 下標與此類似,但是不使用方括號而是花括號。例如:
%scientists = ( "Newton" => "Isaac", "Einstein" => "Albert", "Darwin" => "Charles", "Feynman" => "Richard", );
print "Darwin's First Name is ", $scientists{"Darwin"}, "\n";
Slices 片段¶
通常對雜湊或陣列一次訪問一個元素. 也可以使用下標對列表元素進行訪問.
$whoami = $ENV{"USER"}; # one element from the hash $parent = $ISA[0]; # one element from the array $dir = (getpwnam("daemon"))[7]; # likewise, but with list
片段可以一次訪問列表,陣列或雜湊中的幾個元素, 這是透過列表下標來實現的. 這比分別寫出每個值要方便一些.
($him, $her) = @folks[0,-1]; # array slice @them = @folks[0 .. 3]; # array slice ($who, $home) = @ENV{"USER", "HOME"}; # hash slice ($uid, $dir) = (getpwnam("daemon"))[2,7]; # list slice
既然可以給列表賦值, 當然也可以雜湊或陣列的片段賦值.
@days[3..5] = qw/Wed Thu Fri/; @colors{'red','blue','green'} = (0xff0000, 0x0000ff, 0x00ff00); @folks[0, -1] = @folks[-1, 0];
上面的操作與下列語句等價:
($days[3], $days[4], $days[5]) = qw/Wed Thu Fri/; ($colors{'red'}, $colors{'blue'}, $colors{'green'}) = (0xff0000, 0x0000ff, 0x00ff00); ($folks[0], $folks[-1]) = ($folks[-1], $folks[0]);
既然改變片段就會改變陣列或雜湊的原始值, 那麼`foreach' 結構可以部分或全部地改變陣列或雜湊的值.
foreach (@array[ 4 .. 10 ]) { s/peter/paul/ }
foreach (@hash{qw[key1 key2]}) { s/^\s+//; # trim leading whitespace s/\s+$//; # trim trailing whitespace s/(\w+)/\u\L$1/g; # "titlecase" words }
空列表的片段還是空列表, 因此:
@a = ()[1,0]; # @a has no elements @b = (@a)[0,1]; # @b has no elements @c = (0,1)[2,3]; # @c has no elements
但是:
@a = (1)[1,0]; # @a has two elements @b = (1,undef)[1,0,2]; # @b has three elements
下例利用了這一特性,當返回空列表時迴圈終止:
while ( ($home, $user) = (getpwent)[7,0]) { printf "%-8s %s\n", $user, $home; }
我們在前面說過, 標量上下文中的列表賦值返回值是右側的元素個數. 空列表沒有元素, 所以當口令檔案讀完後, 返回值是0而不是2.
為什麼對雜湊的片段使用'@'而不是'%'呢. 因為括號的型別(方括號或花括號)決定了它是陣列還是雜湊. 而陣列或雜湊的開始字元('$'或'@')表示返回值是單個值還是多個值(列表).
Typeglobs and Filehandles 全域性型別和檔案控制代碼¶
Perl 使用叫做 全域性型別 的型別來支援整個符號表項. 全域性型別的字首是*, 因為它表示所有的型別. 這在過去通常用來給函式傳遞陣列或雜湊的引用, 但是現在有了真正的引用, 這就幾乎不需要了.
現在,全域性型別的主要用途是建立符號表別名. 如下賦值:
*this = *that;
使得$this 成為 $that的別名, @this 成為 @that的別名,%this 成為 %that的別名, &this 成為 &that的別名, 等等. 使用引用會更安全. 這樣:
local *Here::blue =\$There::green;
暫時使 $Here::blue 成為 $There::green的別名, 但不會使 @Here::blue 成為 @There::green的別名, 也不會使 %Here::blue 成為 %There::green的別名, 等等. 參見 perlmod 中的 Symbol Tables 有多個例子. 看起來可能有些怪異, 不過這卻是整個import/export系統的基礎.
全域性型別的其它用途還有, 給函式傳輸檔案控制代碼或是建立新的檔案控制代碼. 如果你要使用全域性型別代替檔案控制代碼, 可以這樣做:
$fh = *STDOUT;
或者使用真正的引用, 象這樣:
$fh =\*STDOUT;
參見 perlsub 有關於間接控制代碼的多個例子.
全域性型別也是使用local() 建立區域性檔案控制代碼的一種方法. 作用範圍在當前塊之內, 但是可以被傳回.例如:
sub newopen { my $path = shift; local *FH; # not my! open (FH, $path) or return undef; return *FH; } $fh = newopen('/etc/passwd');
既然我們有*foo{THING} 這樣的記法, 全域性型別不再多用於檔案控制代碼,但在從函式傳出或向函式傳入新的檔案控制代碼時它還是必需的.因為*HANDLE{IO} 只有在HANDLE 已經是檔案控制代碼時才起作用. 換言之, 在建立新符號表項時必須使用 *FH; *foo{THING} 是不行的. 不知道該用誰時, 使用 *FH
所有能建立檔案控制代碼的函式 (open(), opendir(), pipe(), socketpair(), sysopen(), socket(), 和 accept()) ,在傳遞給它們的控制代碼是標量時,會自動建立一個匿名控制代碼. 這使得象open(my $fh, ...) 和 open(local $fh,...) 這樣的結構可以建立一個在超出範圍時可以自動關閉的控制代碼,如果沒有另外的對它們的引用的話. 這大大減少了全域性型別的使用,當需要開啟一個可以到處使用的控制代碼時, 可以這樣做:
sub myopen { open my $fh, "@_" or die "Can't open '@_': $!"; return $fh; }
{ my $f = myopen("</etc/motd"); print <$f>; # $f implicitly closed here }
注意如果使用了初始化的標量,那麼結果會有不同:`my $fh='zzz'; open($fh, ...)' 與`open( *{'zzz'}, ...)' 等價。`use strict 'refs'' 禁止了這樣做。
另一個建立匿名控制代碼的方法是用Symbol 模組或IO::Handle 模組或諸如此類的東西. These modules have the advantage of not hiding different types of the same name during the local(). 在 open() in the perlfunc manpage 的文末有個例子.(譯者注:說實話,對匿名控制代碼我現在也是一頭霧水,翻譯的不當之處,請高手指出.)
SEE ALSO 參見¶
參見 the perlvar manpage 瞭解 Perl的內建變數和合法變數。參見the perlref manpage, the perlsub manpage, 和 Symbol Tables in the perlmod manpage 瞭解全域性型別和 *foo{THING} 語法。
中文版維護人¶
redcandle <redcandle51@nospam.chinaren.com>
中文版最新更新¶
2001年12月4日星期二
中文手冊頁翻譯計劃¶
跋¶
本頁面中文版由中文
man 手冊頁計劃提供。
中文 man
手冊頁計劃:https://github.com/man-pages-zh/manpages-zh
2003-11-25 | perl v5.8.3 |