內容

名稱

perldata - Perl 資料類型

說明

變數名稱

Perl 有三種內建資料類型:純量、純量陣列,以及純量關聯式陣列,稱為「雜湊」。純量是單一字串(大小不限,僅受可用記憶體限制)、數字,或對某項內容的參考(這會在 perlref 中討論)。一般陣列是從 0 開始編號的純量有序清單。雜湊是純量值的無序集合,其索引為關聯的字串鍵。

值通常會以名稱或透過命名參照來參照。名稱的第一個字元會告訴您它參照哪種類型的資料結構。名稱的其餘部分會告訴您它參照的特定值。通常這個名稱會是一個單一的識別碼,也就是一個以字母或底線開頭,並包含字母、底線和數字的字串。在某些情況下,它可能是由識別碼組成的鏈,以 ::(或已棄用的 ')分隔;除了最後一個識別碼之外,所有識別碼都會被解釋為套件的名稱,用於找到要查詢最後一個識別碼的命名空間(有關詳細資訊,請參閱 perlmod 中的「套件」)。有關識別碼的更深入討論,請參閱 「識別碼剖析」。您可以用一個在執行時期產生值參照的表達式,來取代一個簡單的識別碼。這會在下方和 perlref 中更詳細地說明。

Perl 也有自己的內建變數,其名稱不遵循這些規則。它們有奇怪的名稱,所以它們不會意外地與您的其中一個常規變數發生衝突。與正規表達式的括號部分相符的字串會儲存在名稱中,名稱中只包含 $ 之後的數字(請參閱 perlopperlre)。此外,幾個提供 Perl 內部運作視窗的特殊變數,其名稱包含標點符號。這些變數會在 perlvar 中記載。

純量值總是會以「$」命名,即使是在參照陣列或雜湊的一部分的純量時也是如此。「$」符號在語義上就像英文單字「the」一樣,表示預期只有一個值。

$days		# the simple scalar value "days"
$days[28]		# the 29th element of array @days
$days{'Feb'}	# the 'Feb' value from hash %days
$#days		# the last index of array @days

整個陣列(以及陣列和雜湊的切片)會以「@」表示,其作用很像英文中的「these」或「those」,表示預期有多個值。

@days		# ($days[0], $days[1],... $days[n])
@days[3,4,5]	# same as ($days[3],$days[4],$days[5])
@days{'a','c'}	# same as ($days{'a'},$days{'c'})

整個雜湊會以「%」表示。

%days		# (key1, val1, key2, val2 ...)

此外,子常式會以開頭的「&」命名,儘管在沒有歧義時這是可選的,就像英文中的「do」這個字通常是多餘的一樣。符號表條目可以用開頭的「*」命名,但您現在(如果有的話 :-)還不太在意這個。

每個變數類型都有自己的命名空間,幾個非變數識別碼也是如此。這表示您可以不用擔心衝突,對純量變數、陣列或雜湊使用相同的名稱,或者對檔案處理、目錄處理、子常式名稱、格式名稱或標籤使用相同的名稱。這表示 $foo 和 @foo 是兩個不同的變數。這也表示 $foo[1] 是 @foo 的一部分,而不是 $foo 的一部分。這可能看起來有點奇怪,但沒關係,因為它就是很奇怪。

由於變數參照總是會以「$」、「@」或「%」開頭,因此「保留」字詞實際上並未保留變數名稱。不過,它們確實保留標籤和檔案處理,標籤和檔案處理沒有開頭的特殊字元。例如,您不能有一個名為「log」的檔案處理。提示:您可以說 open(LOG,'logfile') 而不是 open(log,'logfile')。使用大寫檔案處理也可以提高可讀性,並保護您免於與未來的保留字詞發生衝突。大小寫很重要——「FOO」、「Foo」和「foo」都是不同的名稱。以字母或底線開頭的名稱也可以包含數字和底線。

可以將此類字母數字名稱替換為傳回適當類型參考的表達式。如需相關說明,請參閱 perlref

以數字開頭的名稱只能包含更多數字。未以字母、底線、數字或插入符號開頭的名稱限於一個字元,例如 $%$$。(這些單字元名稱大多在 Perl 中有預先定義的意義。例如,$$ 是目前的處理程序 ID。所有此類名稱都保留供 Perl 可能使用。)

識別碼解析

在 Perl 5.18 之前,有效識別碼的實際規則有點模糊。不過,一般來說,這裡定義的任何內容都應該適用於先前版本的 Perl,而相反的情況(在先前版本中運作但未在此定義的邊緣案例)可能無法在較新版本中運作。作為一個重要的附註,請注意,以下內容僅適用於 Perl 原始碼中找到的裸字識別碼,不適用於透過符號參考引入的識別碼,後者的限制較少。如果在 use utf8; pragma 的影響下運作,則套用以下規則

/ (?[ ( \p{Word} & \p{XID_Start} ) + [_] ])
  (?[ ( \p{Word} & \p{XID_Continue} ) ]) *    /x

也就是說,「開始」字元後接任意數量的「繼續」字元。Perl 要求識別碼中的每個字元也符合 \w (這可避免一些有問題的案例);此外,Perl 也接受以底線開頭的識別碼名稱。

如果不在 use utf8 之下,則將來源視為 ASCII + 128 個額外的通用字元,而識別碼應符合

/ (?aa) (?!\d) \w+ /x

也就是說,ASCII 範圍內的任何字元,只要第一個字元不是數字即可。

Perl 中有兩個套件分隔符號:雙冒號 (::) 和單引號 (')。使用 ' 作為套件分隔符號已不建議使用,且將在 Perl 5.40 中移除。正常的識別碼可以用雙冒號開頭或結尾,且可以包含由雙冒號分隔的數個部分。單引號有類似的規則,但例外情況是它們不能在識別碼的結尾:也就是說,$'foo$foo'bar 是合法的,但 $foo'bar' 則不是。

此外,如果識別碼之前有符號(也就是說,如果識別碼是變數名稱的一部分),則可以選擇用大括弧括起來。

雖然可以將雙冒號與單引號混合使用,但引號必須在冒號之後:$::::'foo$foo::'bar 是合法的,但 $::'::foo$foo'::bar 則不是。

綜合來說,用於比對基本識別碼的語法變為

/
 (?(DEFINE)
     (?<variable>
         (?&sigil)
         (?:
                 (?&normal_identifier)
             |   \{ \s* (?&normal_identifier) \s* \}
         )
     )
     (?<normal_identifier>
         (?: :: )* '?
          (?&basic_identifier)
          (?: (?= (?: :: )+ '? | (?: :: )* ' ) (?&normal_identifier) )?
         (?: :: )*
     )
     (?<basic_identifier>
       # is use utf8 on?
         (?(?{ (caller(0))[8] & $utf8::hint_bits })
             (?&Perl_XIDS) (?&Perl_XIDC)*
           | (?aa) (?!\d) \w+
         )
     )
     (?<sigil> [&*\$\@\%])
     (?<Perl_XIDS> (?[ ( \p{Word} & \p{XID_Start} ) + [_] ]) )
     (?<Perl_XIDC> (?[ \p{Word} & \p{XID_Continue} ]) )
 )
/x

同時,特殊識別碼不遵循上述規則;在大部分情況下,此類別中的所有識別碼都有 Perl 給予的特殊意義。由於它們有特殊的解析規則,因此通常無法完全限定。它們有六種形式 (但不要使用形式 5 和 6)

  1. 符號,後接僅符合 \p{POSIX_Digit} 的數字,例如 $0$1$10000

  2. 符號後接一個與 \p{POSIX_Punct} 屬性相符的單一字元,例如 $!%+,但字元 "{" 無效。

  3. 符號後接一個插入符號和 [][A-Z^_?\] 中的任一字元,例如 $^V$^]

  4. 與上述類似,符號後接大括弧中的裸字元文字,其中第一個字元為插入符號。下一個字元為 [][A-Z^_?\] 中的任一字元,後接 ASCII 字元字元。範例為 ${^GLOBAL_PHASE}

  5. 符號後接 [\xA1-\xAC\xAE-\xFF] 範圍內的任何單一字元,但不在 "use utf8" 之下。(在 "use utf8" 之下,套用本節稍早提供的正常識別碼規則。)自 v5.26.0 起,已禁止使用非圖形字元(C1 控制碼、不換行空白和軟連字號)。使用其他字元並不明智,因為這些字元都保留給 Perl 使用,且目前沒有任何一個字元具有特殊意義,儘管這可能會在未通知的情況下變更。

    請注意,此形式的含意是,有些識別碼僅在 "use utf8" 之下合法,反之亦然,例如識別碼 $état"use utf8" 之下合法,但否則會被視為單一字元變數 後接裸字元 "tat",此組合為語法錯誤。

  6. 這是前兩個形式的組合。僅在不在 "use utf8" 之下時才有效(在 "use utf8" 之下時套用正常識別碼規則)。此形式為符號後接大括弧中的文字,其中第一個字元為 [\x80-\xFF] 範圍內的任一字元,後接 ASCII 字元字元,直到尾端大括弧。

    與前一個形式相同的注意事項:非圖形字元不再允許與 "use utf8" 一起使用,最好完全不要使用此形式,而 utf8ness 會造成很大的差異。

在 Perl v5.24 之前,非圖形 ASCII 控制字元在某些情況下也允許使用;自 v5.20 起已不建議使用。

背景

在 Perl 中,運算式和值的詮釋有時取決於運算式或值周圍背景的需求。有兩個主要的背景:清單和純量。某些運算式會在需要清單的背景中傳回清單值,否則傳回純量值。如果運算式有這個特性,會在該運算式的文件說明中提到。換句話說,Perl 會根據預期的傳回值是單數還是複數來重載某些運算式。英文中有些字詞也有這種特性,例如「魚」和「綿羊」。

反過來說,運算式會為其每個參數提供純量或清單背景。例如,如果您說

int( <STDIN> )

整數運算式會為 <> 運算子提供純量背景,而 <> 運算子會回應這個背景,從 STDIN 讀取一行並傳回給整數運算式,然後整數運算式會找出該行的整數值並傳回。另一方面,如果您說

sort( <STDIN> )

那麼 sort 運算式會為 <> 提供清單背景,而 <> 會繼續讀取每個可用的行,直到檔案結束,並將該行清單傳回給 sort 常式,然後 sort 常式會對這些行進行排序,並將它們作為清單傳回給 sort 的背景。

指派有一點特別,它使用其左邊參數來決定右邊參數的背景。指派給純量會在純量背景中評估右側,而指派給陣列或雜湊會在清單背景中評估右側。指派給清單(或切片,它只是一個清單)也會在清單背景中評估右側。

當您使用 use warnings 實用程式或 Perl 的 -w 命令列選項時,您可能會看到關於在「空背景」中無用地使用常數或函式的警告。空背景只表示值已被捨棄,例如只包含 "fred";getpwuid(0); 的陳述式。對於關心是否在清單背景中被呼叫的函式,它仍然算作純量背景。

使用者定義的子常式可以選擇關心它們是在空、純量或清單背景中被呼叫。不過,大多數子常式不需要費心。這是因為純量和清單都會自動內插到清單中。請參閱 perlfunc 中的「wantarray」,了解如何動態辨別函式的呼叫背景。

純量值

Perl 中的所有資料都是純量、純量陣列或純量雜湊。純量可能包含一個單一值,有下列三種不同的形式:數字、字串或參考。一般而言,從一種形式轉換成另一種形式是透明的。儘管純量無法直接儲存多個值,但它可以包含對陣列或雜湊的參考,而陣列或雜湊本身包含多個值。

純量不一定是某種東西或另一種東西。沒有地方可以宣告純量變數為「字串」類型、「數字」類型、「參考」類型或其他任何類型。由於純量的自動轉換,傳回純量的運算不需要在意(事實上,無法在意)呼叫者是在尋找字串、數字或參考。Perl 是一種上下文多態語言,其純量可以是字串、數字或參考(包括物件)。儘管字串和數字在幾乎所有目的上都被視為相同,但參考是強類型、無法轉型的指標,內建參考計數和解構函式呼叫。

如果純量值未定義、為空字串或數字 0(或其字串等效值「0」),則在布林意義上會被解釋為 FALSE,如果為其他任何值,則為 TRUE。布林文脈只是一個特殊類型的純量文脈,其中永遠不會執行轉換為字串或數字。透過 !not 對 true 值進行否定會傳回一個特殊的 false 值。當評估為字串時,它會被視為 "",但作為數字時,它會被視為 0。大多數傳回 true 或 false 的 Perl 運算子都會以這種方式運作。

實際上,空字串(有時稱為「空白」字串)有兩個種類,一個已定義,一個未定義。已定義的版本只是一個長度為零的字串,例如 ""。未定義的版本是一個值,表示某個東西沒有真實的值,例如當發生錯誤時、檔案結束時或當您參考未初始化的變數或陣列或雜湊的元素時。儘管在 Perl 的早期版本中,未定義的純量在第一次在預期定義值的地方使用時可能會變成已定義,但除了 perlref 中說明的自動化例示的罕見情況外,這不再會發生。您可以使用 defined() 運算子來判斷純量值是否已定義(這對陣列或雜湊沒有意義),並使用 undef() 運算子來產生未定義的值。

要找出給定的字串是否為有效的非零數字,有時測試它與數字 0 和詞彙「0」兩者是否相符就足夠了(儘管如果開啟警告,這會造成雜訊)。這是因為不是數字的字串會計為 0,就像在 awk 中一樣

    if ($str == 0 && $str ne "0")  {
	warn "That doesn't look like a number";
    }

這種方法可能是最好的,因為否則您無法正確處理 IEEE 符號,例如 NaNInfinity。在其他時候,您可能希望透過呼叫 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 的長度,就像在 csh 中一樣。不過,這並不是陣列的長度;它是最後一個元素的腳本,這是一個不同的值,因為通常會有第 0 個元素。指定給 $#days 實際上會改變陣列的長度。以這種方式縮短陣列會刪除中間值。將先前縮短的陣列加長不會復原那些元素中的值。

您也可以透過預先擴充即將變大的陣列來獲得一些微小的效率測量。您也可以透過指定給陣列末端的元素來擴充陣列。您可以透過指定空清單 () 給陣列來將陣列截斷為空。下列為等效的

@whatever = ();
$#whatever = -1;

如果您在純量內容中評估陣列,它會傳回陣列的長度。(請注意,這不適用於清單,清單會傳回最後一個值,就像 C 逗號運算子一樣,也不適用於內建函數,內建函數會傳回它們想傳回的任何內容。)下列永遠為真

scalar(@whatever) == $#whatever + 1;

有些程式設計師選擇使用明確轉換,以便不留下任何疑問

$element_count = scalar(@whatever);

如果您在純量內容中評估雜湊,如果雜湊為空,它會傳回 false 值。如果有任何鍵/值配對,它會傳回 true 值。更精確的定義取決於版本。

在 Perl 5.25 之前,傳回的值是一個字串,包含已使用的儲存區數目和已配置的儲存區數目,中間以斜線分隔。這幾乎只對找出 Perl 的內部雜湊演算法是否在您的資料集上執行不佳有幫助。例如,您將 10,000 個東西放入雜湊中,但在純量內容中評估 %HASH 會顯示 "1/16",這表示十六個儲存區中只有一個被觸及,而且可能包含您所有的 10,000 個項目。這不應該發生。

從 Perl 5.25 開始,傳回值已變更為雜湊中鍵的計數。如果您需要存取舊行為,您可以改用 Hash::Util::bucket_ratio()

如果在標量語境中評估繫結雜湊,則會呼叫 SCALAR 方法(備用為 FIRSTKEY)。

您可以透過指派給 keys() 函式來預先配置雜湊空間。這會將配置的儲存區四捨五入至下一個 2 的次方

keys(%users) = 1000;		# allocate 1024 buckets

標量值建構函式

數字文字以任何下列浮點或整數格式指定

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 (only numbers, begins with 0)
0o12_345            # alternative octal (introduced in Perl 5.33.5)
0b011011            # binary
0x1.999ap-4         # hexadecimal floating point (the 'p' is required)

您可以在數字文字中使用底線(底線)在數字之間以提高可讀性(但不能在同一列中使用多個底線:23__500 不合法;23_500 合法)。例如,您可以將二進制數字分組為三組(例如 Unix 風格的模式參數,例如 0b110_100_100)或四組(表示半位元組,例如 0b1010_0110)或其他組。

字串文字通常以單引號或雙引號分隔。它們的工作方式與標準 Unix shell 中的引號非常相似:雙引號字串文字會受到反斜線和變數替換的影響;單引號字串則不會(\'\\ 除外)。通常的 C 風格反斜線規則適用於建立換行、標籤等字元,以及一些更特別的形式。請參閱 perlop 中的「引號和類似引號的運算子」 以取得清單。

字串文字中的十六進制、八進制或二進制表示法(例如 '0xff')不會自動轉換為其整數表示法。hex() 和 oct() 函式會為您進行這些轉換。請參閱 perlfunc 中的「hex」perlfunc 中的「oct」 以取得更多詳細資料。

十六進制浮點數可以像十六進制文字一樣開始,並且可以接續一個可選的十六進制小數部分,但它必須接續 p、一個可選符號和一個 2 的次方。此格式對於準確呈現浮點數值、避免轉換為或從十進制浮點數轉換,因此避免可能精確度損失很有用。請注意,雖然大多數當前平台都使用 64 位元 IEEE 754 浮點數,但並非所有平台都使用。另一個潛在的(低階)差異來源是浮點數捨入模式,它可能因 CPU、作業系統和編譯器而異,而 Perl 無法控制。

您也可以將換行符號直接嵌入字串中,亦即它們可以結束在與開始不同的行上。這很好,但如果您忘記尾隨引號,則錯誤不會報告,直到 Perl 找到包含引號字元的另一行,這可能在指令碼中更後面的位置。字串內的變數替換僅限於標量變數、陣列和陣列或雜湊切片。(換句話說,名稱以 $ 或 @ 開頭,後面接續一個可選的括號表達式作為下標。)下列程式碼片段會列印出「價格為 $100。」

$Price = '$100';	# not interpolated
print "The price is $Price.\n";	# interpolated

Perl 中沒有雙重內插,因此 $100 保持原樣。

預設情況下,字串內置換的浮點數數字會使用句點 (".") 作為小數點分隔符號。如果 use locale 生效,且已呼叫 POSIX::setlocale(),則用於小數點分隔符號的字元會受到 LC_NUMERIC 區域設定影響。請參閱 perllocalePOSIX

使用大括號標示變數名稱

如同某些 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{2.0}++ 等同於 $version{2}++,而不是 $version{'2.0'}++

在內插看起來像是陣列或雜湊存取符號的文字時,會出現類似的問題。將簡單變數 (例如 $who) 直接置於 "[1]""{foo}" 等文字前面,會導致變數內插為存取 @who 的元素或儲存在 %who 中的值

$who = "Larry Wall";
print "$who[1] is the father of Perl.\n";

會嘗試存取名為 @who 的陣列的索引 1。同樣地,使用大括號可以防止這種情況發生

$who = "Larry Wall";
print "${who}[1] is the father of Perl.\n";

會被視為與下列相同

$who = "Larry Wall";
print $who . "[1] is the father of Perl.\n";

此符號也適用於更複雜的變數描述,例如帶有標記的陣列或雜湊存取。例如

@name = qw(Larry Curly Moe);
print "Also ${name[0]}[1] was a member\n";

如果不使用大括號,上述範例會被解析為 @name 陣列中的二級陣列標記,且在 use strict 下可能會產生致命例外,因為它會被解析成這樣

print "Also " . $name[0][1] . " was a member\n";

而非預期

print "Also " . $name[0] . "[1] was a member\n";

使用反斜線於下標或套件符號的第一個字元,而該字元並非您要存取變數的一部分,也可以得到類似的結果。因此,上述範例也可以寫成

@name = qw(Larry Curly Moe);
print "Also $name[0]\[1] was a member\n";

然而,對於某些特殊變數(多字元插入符號變數),使用大括號的劃分形式是您唯一可以參照該變數的方式,也是您唯一可以透過內插存取該變數的下標方式。

考慮由正規表示式引擎填入模式中所有擷取緩衝區內容的神奇陣列 @{^CAPTURE}(請參閱 perlvarperlre)。在字串中存取這些成員的唯一方式是透過括號(劃分)形式

"abc"=~/(.)(.)(.)/
    and print "Second buffer is ${^CAPTURE[1]}";

等於

"abc"=~/(.)(.)(.)/
    and print "Second buffer is " . ${^CAPTURE}[1];

@^CAPTURE 是語法錯誤,因此必須參照為 @{^CAPTURE},且要在一般程式碼中存取其元素之一,您會寫 ${^CAPTURE}[1] 。然而,在字串中內插時,"${^CAPTURE}[1]" 會等於 ${^CAPTURE} . "[1]",這甚至不會參照同一個變數!因此,下標必須置於大括號內部"${^CAPTURE[1]}"

使用大括號的劃分形式可以用於所有不同類型的變數存取,包括陣列和雜湊切片。例如,下列類型的程式碼

@name = qw(Larry Curly Moe);
local $" = " and ";
print "My favorites were @{name[1,2]}.\n";

會輸出

My favorites were Curly and Moe.

特殊浮點數:無窮大(Inf)和非數字(NaN)

浮點數值包括特殊值 InfNaN,分別代表無窮大和非數字。無窮大也可以是負值。

無窮大是某些數學運算溢位浮點數範圍的結果,例如 9**9**9。非數字是結果未定義或無法表示時的結果。不過,請注意,您無法從某些常見的「未定義」或「超出範圍」運算(例如除以零或負數的平方根)取得 NaN,因為 Perl 會為這些運算產生致命錯誤。

無窮大和非數字有其專屬的運算規則。一般規則是它們具有「傳染性」:Inf 加一為 InfNaN 加一為 NaN。有趣的地方在於當你組合無窮大和非數字時:InfInfInf 除以 InfNaN(而 InfInfInfInf 乘以 InfInf)。NaN 也令人好奇,因為它不等於任何數字,包括它自己:NaN != NaN

Perl 不會將 InfNaN 視為數字字面量,但你可以將它們作為字串,Perl 會視需要轉換它們:「Inf」+ 1。(不過,你可以從 POSIX 延伸模組匯入它們;use POSIX qw(Inf NaN); 然後將它們用作字面量。)

請注意,在輸入(字串轉數字)時,Perl 會以多種形式接受 InfNaN。它會忽略大小寫,並瞭解 Win32 特定的形式,例如 1.#INF,但在輸出時,這些值會正規化為 InfNaN

版本字串

v1.20.300.4000 形式的字面量會解析為由指定序數的字元組成的字串。此形式稱為 v 字串,它提供了一種替代的、更易於閱讀的方式來建構字串,而不是使用不太易於閱讀的內插形式 "\x{1}\x{14}\x{12c}\x{fa0}"。這對於表示 Unicode 字串以及使用字串比較運算子(cmpgtlt 等)比較版本「數字」很有用。如果字面量中有兩個或更多個點,則可以省略開頭的 v

print v9786;              # prints SMILEY, "\x{263a}"
print v102.111.111;       # prints "foo"
print 102.111.111;        # same

requireuse 都接受此類字面量來執行版本檢查。請注意,除非你也使用 Socket 套件的 inet_aton()/inet_ntoa() 常式,否則將 v 字串用於 IPv4 位址並非可攜式的。

請注意,自 Perl 5.8.1 起,單數字 v 字串(例如 v65)在 => 運算子(通常用於將雜湊鍵與雜湊值分開)之前並非 v 字串;相反地,它們會被解釋為字串字面量('v65')。它們在 Perl 5.6.0 到 Perl 5.8.0 之間是 v 字串,但那造成更多混淆和損壞,而非好處。多數字 v 字串,例如 v65.6665.66.67,始終是 v 字串。

特殊字面值

特殊字面值 __FILE__, __LINE__ 和 __PACKAGE__ 分別代表程式中當前檔案名稱、行號和套件名稱。__SUB__ 則提供當前子程式的參考。它們只能作為單獨的記號使用;不會內插到字串中。如果沒有當前套件(由於 package; 指令為空),__PACKAGE__ 則為未定義值。(不過自 5.10 版起,已不再支援空的 package;。)在子程式外,__SUB__ 為未定義值。__SUB__ 僅在 5.16 或更高版本中可用,且僅在宣告 use v5.16use feature "current_sub" 時可用。

兩個控制字元 ^D 和 ^Z,以及記號 __END__ 和 __DATA__ 可用於指出實際檔案結束前指令碼的邏輯結束。除非程式依以下說明讀取,否則詮釋器會忽略任何後續文字。

__DATA__ 之後的文字可透過檔案句柄 PACKNAME::DATA 讀取,其中 PACKNAME 是在遇到 __DATA__ 記號時當前的套件。檔案句柄會保持開啟狀態,指向 __DATA__ 之後的行。程式應在讀取完畢後 close DATA。(如果模組因任何原因重新載入,讓它保持開啟狀態會造成檔案句柄外洩,因此關閉它是一種更安全的做法。)為了與在引入 __DATA__ 之前撰寫的舊指令碼相容,__END__ 在頂層指令碼中會像 __DATA__ 一樣運作(但在使用 requiredo 載入的檔案中則不會),並讓檔案的剩餘內容可透過 main::DATA 存取。

while (my $line = <DATA>) { print $line; }
close DATA;
__DATA__
Hello world.

預設情況下,DATA 檔案句柄具有 Perl 在讀取檔案以剖析來源時所使用的任何 PerlIO 層。這通常表示檔案是以位元組方式讀取的,就像是以 Latin-1 編碼一樣,但有兩個主要方法可以讓它有所不同。首先,如果 __END__/__DATA__ 記號在 use utf8 實用的範圍內,則 DATA 句柄將會處於 UTF-8 模式。其次,如果來源是從 Perl 的標準輸入讀取的,則 DATA 檔案句柄實際上會別名為 STDIN 檔案句柄,並且可能會因為 PERL_UNICODE 環境變數或 Perl 的命令列開關而處於 UTF-8 模式。

請參閱 SelfLoader 以取得 __DATA__ 的更多說明,以及其使用範例。請注意,您無法在 BEGIN 區塊中從 DATA 檔案句柄讀取:BEGIN 區塊會在看到時立即執行(在編譯期間),此時對應的 __DATA__(或 __END__)記號尚未看到。

裸字

在語法中沒有其他解釋的字詞將被視為引號字串。這些字詞稱為「裸字」。與檔案句柄和標籤一樣,完全由小寫字母組成的裸字有與未來保留字衝突的風險,如果你使用 use warnings 實用程式或 -w 參數,Perl 會警告你任何此類字詞。Perl 將裸字(例如識別碼)限制在約 250 個字元。未來版本的 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] 做出一個良好的猜測,而且幾乎總是正確的。如果它確實猜錯了,或者你只是很偏執,你可以使用上面的大括號強制正確的解釋。

如果你正在尋找有關如何使用這裡文件(以前在這裡)的資訊,它已被移至 perlop 中的「引號和類引號運算子」

清單值建構函式

清單值透過逗號分隔個別值(並在優先順序需要時將清單括在括號中)來表示

(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 文件來指定陣列,每行一個元素,你可以使用類似下列的方法

@sauces = <<End_Lines =~ m/(\S.*\S)/g;
    normal tomato
    spicy tomato
    green chile
    pesto
    white wine
End_Lines

LIST 會自動內插子清單。也就是說,當 LIST 被評估時,清單中的每個元素會在清單內容中被評估,而產生的清單值會內插到 LIST 中,就好像每個個別元素都是 LIST 的成員一樣。因此,陣列和雜湊會在 LIST 中失去它們的身分,LIST

(@foo,@bar,&SomeSub,%glarch)

包含 @foo 的所有元素,接著是 @bar 的所有元素,接著是名為 SomeSub 的子常式在清單內容中呼叫後回傳的所有元素,接著是 %glarch 的鍵/值配對。若要建立一個會內插的清單參考,請參閱 perlref

空清單以 () 表示。將其內插到清單中不會產生任何效果。因此 ((),(),()) 等於 ()。類似地,內插一個沒有元素的陣列,就等於在那個點上沒有內插任何陣列。

這種內插會與以下事實結合:開頭和結尾的括號是可選的(除非在優先順序上需要),而且清單可以用一個可選的逗號結尾,表示清單中的多個逗號是合法的語法。清單 1,,3 是兩個清單的串接,1,3,其中第一個以那個可選的逗號結尾。1,,3(1,),(3)1,3(而 1,,,3 類似地是 (1,),(,),31,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];

只有當清單中的每個元素本身都可以被指定時,才能指定清單

($x, $y, $z) = (1, 2, 3);

($map{'red'}, $map{'blue'}, $map{'green'}) = (0x00f, 0x0f0, 0xf00);

一個例外是,你可以在清單中指定為 undef。這對於丟棄函數的一些回傳值很有用

($dev, $ino, undef, undef, $uid, $gid) = stat($file);

從 Perl 5.22 開始,你也可以使用 (undef)x2 代替 undef, undef。(你也可以執行 ($x) x 2,這比較沒用,因為它會將值指定給同一個變數兩次,覆蓋第一次指定的變數。)

當你將一個純量清單指定給一個陣列時,該陣列中先前所有的值都會被清除,而陣列中的元素數量現在會等於右手邊清單中的元素數量,也就是進行指定動作的清單。陣列會自動調整大小,以精確容納右手邊清單中的每個元素。

use warnings;
my (@xyz, $x, $y, $z);

@xyz = (1, 2, 3);
print "@xyz\n";                             # 1 2 3

@xyz = ('al', 'be', 'ga', 'de');
print "@xyz\n";                             # al be ga de

@xyz = (101, 102);
print "@xyz\n";                             # 101 102

然而,當你將一個純量清單指定給另一個純量清單時,結果會根據左手邊的清單(也就是被指定到的清單)是否具有與右手邊清單相同、更多或更少的元素而有所不同。

($x, $y, $z) = (1, 2, 3);
print "$x $y $z\n";                         # 1 2 3

($x, $y, $z) = ('al', 'be', 'ga', 'de');
print "$x $y $z\n";                         # al be ga

($x, $y, $z) = (101, 102);
print "$x $y $z\n";                         # 101 102
# Use of uninitialized value $z in concatenation (.)
# or string at [program] line [line number].

如果左手邊清單中的純量數目少於右手邊清單中的純量數目,右手邊清單中的「額外」純量將不會被指定。

如果左手邊清單中的純量數目大於左手邊清單中的純量數目,「遺失」的純量將會變成未定義。

($x, $y, $z) = (101, 102);
for my $el ($x, $y, $z) {
    (defined $el) ? print "$el " : print "<undef>";
}
print "\n";
                                            # 101 102 <undef>

在純量內容中進行清單指定會傳回指定右側表達式所產生的元素數目

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

會將在 $string 中找到的數字組數放入 $count 中。這是因為模式比對是在清單內容中(因為它被指定給空清單),因此會傳回字串中所有相符部分的清單。在純量內容中的清單指定會將其轉換為元素數目(這裡是模式相符的次數),並將其指定給 $count。請注意,僅僅使用

$count = $string =~ /\d+/g;

不會起作用,因為在純量內容中的模式比對只會傳回 true 或 false,而不是相符的次數。

清單指定的最後一個元素可能是陣列或雜湊

($x, $y, @rest) = split;
my($x, $y, %rest) = @_;

您實際上可以在清單中的任何地方放置陣列或雜湊,但清單中的第一個會吸收所有值,而其後的任何值都將變成未定義。這在 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',
};

或用於對複雜函數使用依名稱傳遞參數

$field = $query->radio_group(
            name      => 'group_name',
            values    => ['eenie','meenie','minie'],
            default   => 'meenie',
            linebreak => 'true',
            labels    => \%labels
);

請注意,僅僅因為雜湊是以該順序初始化的,並不表示它會以該順序輸出。請參閱 "sort" in perlfunc 以了解如何安排輸出順序的範例。

如果一個金鑰在雜湊初始化清單中出現多次,最後出現的會獲勝

%circle = (
              center => [5, 10],
              center => [27, 9],
              radius => 100,
              color => [0xDF, 0xFF, 0x00],
              radius => 54,
);

# same as
%circle = (
              center => [27, 9],
              color => [0xDF, 0xFF, 0x00],
              radius => 54,
);

這可以用來提供可覆寫的組態預設值

# values in %args take priority over %config_defaults
%config = (%config_defaults, %args);

下標

陣列可以透過指定美元符號 ($)、陣列名稱 (不含開頭的 @) 以及方括號內的腳本,一次存取一個純量。例如

@myarray = (5, 50, 500, 5000);
print "The Third Element is", $myarray[2], "\n";

陣列索引從 0 開始。負腳本會從結尾擷取其值。在我們的範例中,$myarray[-1] 會是 5000,而 $myarray[-2] 會是 500。

雜湊腳本類似,只是使用大括號而不是方括號。例如

%scientists = 
(
    "Newton" => "Isaac",
    "Einstein" => "Albert",
    "Darwin" => "Charles",
    "Feynman" => "Richard",
);

print "Darwin's First Name is ", $scientists{"Darwin"}, "\n";

您也可以對清單使用腳本,以從中取得單一元素

$dir = (getpwnam("daemon"))[7];

多維陣列模擬

可以使用清單對雜湊使用腳本來模擬多維陣列。清單的元素會與腳本分隔符號結合 (請參閱 "$;" in perlvar)。

$foo{$x,$y,$z}

等於

$foo{join($;, $x, $y, $z)}

預設腳本分隔符號為 "\034",與 awk 中的 SUBSEP 相同。

切片

切片會使用腳本清單,同時存取清單、陣列或雜湊的幾個元素。這比將個別元素寫成獨立純量值的清單更方便。

($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/\b(\w)(\w*)\b/\u$1\L$2/g;     # "titlecase" words
}

作為一個特殊例外,當您切片清單 (但不是陣列或雜湊) 時,如果清單評估為空,則切片該空清單時,結果也會是空清單。因此

@a = ()[0,1];          # @a has no elements
@b = (@a)[0,1];        # @b has no elements
@c = (sub{}->())[0,1]; # @c has no elements
@d = ('a','b')[0,1];   # @d has two elements
@e = (@d)[0,1,8,9];    # @e has four elements
@f = (@d)[8,9];        # @f has two elements

這使得撰寫在傳回空清單時終止的迴圈變得容易

while ( ($home, $user) = (getpwent)[7,0] ) {
    printf "%-8s %s\n", $user, $home;
}

如本文檔前面所述,清單指定純量的意義是指定右側的元素數目。空清單不包含任何元素,因此當密碼檔案用盡時,結果為 0,而不是 2。

純量內容的切片會傳回切片的最後一個項目。

@a = qw/first second third/;
%h = (first => 'A', second => 'B');
$t = @a[0, 1];                  # $t is now 'second'
$u = @h{'first', 'second'};     # $u is now 'B'

如果您對在雜湊切片上使用「@」而不是「%」感到困惑,請這樣想。括號的類型 (方括號或大括號) 決定要查看的是陣列還是雜湊。另一方面,陣列或雜湊上的開頭符號 (「$」或「@」) 表示您要取得單數值 (純量) 還是複數值 (清單)。

金鑰/值雜湊切片

從 Perl 5.20 開始,使用 % 符號的雜湊切片運算是一種切片運算變體,會傳回一個包含鍵值對的清單,而不再只是值

%h = (blonk => 2, foo => 3, squink => 5, bar => 8);
%subset = %h{'foo', 'bar'}; # key/value hash slice
# %subset is now (foo => 3, bar => 8)
%removed = delete %h{'foo', 'bar'};
# %removed is now (foo => 3, bar => 8)
# %h is now (blonk => 2, squink => 5)

然而,這種切片的結果無法被定位或指定。在其他方面,它們與使用 @ 符號的雜湊切片非常一致。

索引/值陣列切片

與鍵值雜湊切片(同樣也是在 Perl 5.20 中引入)類似,% 陣列切片語法會傳回一個包含索引/值對的清單

@a = "a".."z";
@list = %a[3,4,6];
# @list is now (3, "d", 4, "e", 6, "g")
@removed = delete %a[3,4,6]
# @removed is now (3, "d", 4, "e", 6, "g")
# @list[3,4,6] are now undef

請注意,強烈建議不要對陣列值呼叫 delete

類型全域變數和檔案控制代碼

Perl 使用稱為類型全域變數的內部類型來儲存整個符號表項目。類型全域變數的類型前綴為 *,因為它代表所有類型。這曾經是透過參照將陣列和雜湊傳遞到函式的首選方式,但現在我們有了真正的參照,所以很少需要這樣做。

在現代 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 中的「符號表」 以取得更多範例。雖然這看起來很奇怪,但這是整個模組匯入/匯出系統的基礎。

類型全域變數的另一個用途是將檔案控制代碼傳遞到函式或建立新的檔案控制代碼。如果您需要使用類型全域變數來儲存檔案控制代碼,請使用這種方式

$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 模組及其同類。這些模組的優點是在 local() 期間不會隱藏同名的不同類型。請參閱 "open" in perlfunc 的底部以取得範例。

另請參閱

請參閱 perlvar 以取得 Perl 內建變數的說明和合法變數名稱的討論。請參閱 perlrefperlsub"Symbol Tables" in perlmod 以取得有關類型全域變數和 *foo{THING} 語法的更多討論。