Arch manual pages

PERLDATA(7) Perl Programmers Reference Guide PERLDATA(7)

perldata- Perl 數據類型

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。)

在 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” 以瞭解如何辨明你的函數調用時的上下文。

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 空間

數值常量有以下浮點和整數格式:

    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)

在不需要列表的上下文中, 列表的值是最後一個元素的值, 這與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”

數組可以用一個美元符號,加上它的名字(不包括前導的`@'),加上方括號和其中包含的下標來取得值。例如:

    @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";

通常對哈希或數組一次訪問一個元素. 也可以使用下標對列表元素進行訪問.

    $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.

爲什麼對哈希的片段使用'@'而不是'%'呢. 因爲括號的類型(方括號或花括號)決定了它是數組還是哈希. 而數組或哈希的開始字符('$'或'@')表示返回值是單個值還是多個值(列表).

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 的文末有個例子.(譯者注:說實話,對匿名句柄我現在也是一頭霧水,翻譯的不當之處,請高手指出.)

參見 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日星期二

http://cmpp.linuxforum.net

本頁面中文版由中文 man 手冊頁計劃提供。
中文 man 手冊頁計劃:https://github.com/man-pages-zh/manpages-zh
2003-11-25 perl v5.8.3