前言
Perl 程式會根據程式執行時當下的語境來決定其行為,這算是一種 Perl 程式的內隱規則。在這些語境中,比較重要的是純量語境和串列語境,其他的稍微知道一下即可。
純量語境 (Scalar Context)
用 scalar
函式會把參數強制轉為純量語境,例如用 scalar
取得陣列長度:
my @arr = (1, 2, 3);
scalar(@arr) == 3 or die "Wrong length";
不僅透過 scalar
函式可取得純量語境,進行純量的操作也會轉為純量語境,如下例:
my @arr = (1, 2, 3);
@arr + 0 == 3 or die "Wrong length";
+ 0
會使 @arr
轉為純量語境,而陣列在純量語境下會回傳其長度。
指派到純量也會轉為純量語境,如下例:
my @arr = (1, 2, 3);
my $length = @arr;
$length == 3 or die "Wrong length";
同樣地,指派到純量時會強制轉為純量語境,這時 @arr
會回傳其長度。
串列語境 (List Context)
我們在操作串列或陣列時,會轉換至串列語境。像是先前提過的串列指派:
my ($a, $b, $c) = @arr;
如果我們把純量放到串列語境,會變成串列的第一個值,如下例:
my ($a, $b, $c) = 5;
$a == 5 or die "Wrong value";
!defined($b) or die "Wrong value";
!defined($c) or die "Wrong value";
這時候 5
轉變成單一元素的串列,$a
值為 5
,$b
和 $c
則為未定義 undef
。
以下程式是串列語境而非純量語境:
my ($a) = (3, 4, 5);
$a == 3 or die "Wrong value";
這是因為 ($a)
視為單一元素的串列,並省略尾端的逗號。因此,$a
的值為 3
。這算是 Perl 的一個小陷阱。
函式在不同語境的行為
我們在閱讀 Perl 文件時,會發現 Perl 文件在描述函式時,會分別介紹其在純量語境和串列語境的行為,以 reverse
函式為例 (參考這裡):
my @arr = reverse ("foo", "bar", "baz");
my $s = reverse ("foo", "bar", "baz");
scalar(@arr) == 3 or die "Wrong length";
$arr[0] eq "baz" or die "Wrong value";
$arr[1] eq "bar" or die "Wrong value";
$arr[2] eq "foo" or die "Wrong value";
$s eq "zabraboof" or die "Wrong value";
reverse
在串列語境時,會將元素反轉後回傳新的串列;在純量語境,則會將所有元素轉字串、合併、倒轉後回傳該字串。許多 Perl 的函式不論在純量語境或串列語境都能執行,但行為不同,故需注意閱讀文件。
撰寫函式時,要怎麼知道呼叫者的語境呢?Perl 提供 wantarray
函式來判斷 (參考這裡)。本系列文的目標是把 Perl 當成命令列工具,暫時不會深入撰寫函式的細節。
布林語境 (Boolean Context)
布林語境算是一種特殊的純量語境,雖然 Perl 沒有定義真偽值,但在內部會自動判斷。見下例:
if (()) {
die "It should be empty";
}
在這個例子中,空串列 ()
視為偽 (falsy),故不會拋出例外。
布林語境不需刻意學習,因為我們平常在寫判斷句 (conditional) 時,自然而然會用到布林語境。
虛無語境 (Void Context)
虛無語境算是一種特殊的純量語境,發生在程式拋棄回傳值時。例如,我們在以下程式中打開警告訊息:
use warnings;
"Hello World";
這時候程式會拋出以下訊息:
Useless use of a constant ("Hello World") in void context
這是因為我們忽略掉 "Hello World"
所引發的警告訊息。
刻意引發虛無語境對程式沒啥幫助,這通常是忘了處理回傳值所引發的語境。
如果我們想讓函式 func
以串列語境來表現其行為,但不想要其回傳值,可以指派到空串列:
() = func();
相對來說,不接收其回傳值直接執行則會變成虛無語境,如下例:
func();
字串安插語境 (Interpolative Context)
指的是在雙引號中自動解析變數的情形。見下例:
my $name = "Michelle";
my $greeting = "Hello, $name";
$greeting == "Hello Michelle" or die "Wrong value";