位元詩人 [Perl] 程式設計教學:使用運算子 (Operator)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

運算子 (operators) 可執行一些基本的運算,會透過符號而非函式呼叫來使用。一般來說,運算子無法再拆分成更細的項目,所以視為程式語言的基本指令。

不過,有許多語言支援運算子重載 (operator overloading),若某參考型別 (或物件) 重載了某個運算子,該物件就可以像基礎型別般使用運算子。Perl 也支援運算子重載,但我們不在本文介紹這個部分,僅介紹基本的運算子使用方式。

代數運算子 (Arithmetic Operators)

代數運算是指基本的四則運算,包括以下運算子:

  • +:相加
  • -:相減
  • *:相乘
  • /:相除
  • %:取餘數
  • **:取指數

以下是實例:

7 + 3 == 10 or die "Wrong value";
7 - 3 == 4 or die "Wrong value";
7 * 3 == 21 or die "Wrong value";
7 / 3 - 2.333333 < 1 / 100000 or die "Wrong value";
7 % 3 == 1 or die "Wrong value";
7 ** 3 == 7 * 7 * 7 or die "Wrong value";

我們在這裡說明一下 die 的使用方式。die 是 Perl 用來拋出例外的函式 (參考這裡),在這裡用來模擬其他語言的斷言 (assertion),該行程式能順利執行代表程式的條件句為真 (true)。

要注意 / (相除) 的結果會是浮點數;相對來說,% (取餘數) 的結果則會是整數。

關係運算子 (Relational Operators)

關係運算子用於比較兩項資料的大小。Perl 根據比較值為字串或數字需要使用不同的運算子,這是因為 Perl 為弱型別語言,無法直接以帳面上的值判定型別。

以下是 Perl 之中支援數字比較的運算子:

  • ==:相等
  • !=:不相等
  • <=>:相等或不相等
  • >:大於
  • >=:大於等於
  • <:小於
  • <=:小於等於

以下是使用實例:

3 == 3 or die "Wrong relation";
7 != 3 or die "Wrong relation";
7 > 3 or die "Wrong relation";
7 >= 3 or die "Wrong relation";
3 < 7 or die "Wrong relation";
3 <= 7 or die "Wrong relation";

在這些運算子中,<=> 可以同時判定大於、等於、小於三種情境,會分別回傳 10-1。參考下例:

(7 <=> 3) > 0 or die "Wrong relation";

在此處,建議寫 > 0 而不要寫 == 1,因為 <=> 運算子的精神在於用數字的正負判定大小,而非死記回傳的數值。

以下是支援字串比較的運算子:

  • eq:相等
  • ne:不相等
  • cmp:等於或不等於
  • gt:大於
  • ge:大於或等於
  • lt:小於
  • le:小於或等於

使用方式和數字比較相似。以下是實例:

"Perl" eq "Perl" or die "Wrong relation";
"Perl" ne "Ruby" or die "Wrong relation";
"Perl" lt "Ruby" or die "Wrong relation";
"Perl" le "Ruby" or die "Wrong relation";
"Ruby" gt "Perl" or die "Wrong relation";
"Ruby" ge "Perl" or die "Wrong relation";

因為 "R" 在順位上比 "P" 後面 (大),所以會有這樣的比較結果。

如果有在用類 Unix 系統的讀者,會發現 Perl 的關係運算子剛好和 Bash 的關係運算子相反。筆者以為 Perl 的運算子比較好記,因為數字用符號來相較而字串用字串來相較。

邏輯運算子 (Logic Operators)

邏輯運算子用來進行邏輯運算,在實務上用於結合兩個以上的判斷式。Perl 有兩套邏輯運算子,符號型的優先順序較高,而文字型的優先順序幾乎是最低的。以下是高優先順序的邏輯運算子:

  • &&:且 (and)
  • ||:或 (or)
  • !:非 (not)

參考以下例子:

my $true = 1;
my $false = 0;

# AND
($true && $true) == $true or die "Wrong logic";
($true && $false) == $false or die "Wrong logic";
($false && $true) == $false or die "Wrong logic";
($false && $false) == $false or die "Wrong logic";

# OR
($true || $true) == $true or die "Wrong logic";
($true || $false) == $true or die "Wrong logic";
($false || $true) == $true or die "Wrong logic";
($false || $false) == $false or die "Wrong logic";

# NOT
!$true == $false or die "Wrong logic";
!$false == $true or die "Wrong logic";

由於 Perl 沒有真正的真偽值,故我們在範例中分別將 10 做為 $true$false

以下則是低優先順序的邏輯運算子:

  • and:且
  • or:或
  • xor:互斥或
  • not:非

註:xor 僅在兩者真偽相異時才會成立。

以下是範例:

my $true = 1;
my $false = 0;

# AND
($true and $true) == $true or die "Wrong logic";
($true and $false) == $false or die "Wrong logic";
($false and $true) == $false or die "Wrong logic";
($false and $false) == $false or die "Wrong logic";

# OR
($true or $true) == $true or die "Wrong logic";
($true or $false) == $true or die "Wrong logic";
($false or $true) == $true or die "Wrong logic";
($false or $false) == $false or die "Wrong logic";

# XOR
($true xor $true) == $false or die "Wrong logic";
($true xor $false) == $true or die "Wrong logic";
($false xor $true) == $true or die "Wrong logic";
($false xor $false) == $false or die "Wrong logic";

# NOT
(not $true) == $false or die "Wrong logic";
(not $false) == $true or die "Wrong logic";

如果覺得邏輯比較複雜,建議直接用 () 括號提升運算子優先次序,這樣程式碼會比較好讀。

指派運算子 (Assignment Operators)

除了最常用的 = 運算子之外,其他的運算子算是一種減少程式碼的語法糖。Perl 的指派運算子如下:

  • =:指派值
  • +=:相加後指派回原變數
  • -=:相減後指派回原變數
  • *=:相乘後指派回原變數
  • /=:相除後指派回原變數
  • %=:取餘數後指派回原變數
  • **=:取指數後挀派回原變數

以下是實例:

my $n = 3;

$n += 4;
$ == 7 or die "Wrong value";

二元運算子 (Bitwise Operators)

二元運算子主要用於低階運算 (low-level computing) 中加速程式的一些手法,Perl 算相對高階的語言,不過仍保有二元運算的特性。以下是 Perl 的二元運算子:

  • &:bitwise and
  • |:bitwise or
  • ^:bitwise xor
  • ~:bitwise not
  • <<:左移 (left shift)
  • >>:右移 (right shift)

以下是實例:

my $a = 0b0011;
my $b = 0b0101;

($a & $b) == 0b0001 or die "Wrong value";
($a | $b) == 0b0111 or die "Wrong value";
($a ^ $b) == 0b0110 or die "Wrong value";

由於 Perl 可以直接將二進位數寫出來,必要時可將數字實字寫成二進位數,相對較易讀。

二元運算其中一個用途是用來當成一種旗標 (flag),參考以下例子:

my $exec  = 1;       # 0001
my $write = 1 << 1;  # 0010
my $read  = 1 << 2;  # 0100

($read ^ $write) == 6 or die "Wrong value";
($read ^ $exec) == 5 or die "Wrong value";
($read ^ $write ^ $exec) == 7 or die "Wrong value";

在此處由於我們使用二元運算,所以可以使程式碼較簡潔。

字串相關的運算子

Perl 提供以下兩種字串相關運算子:

  • .:相接
  • x:重覆

以下是實例:

"abc" . "def" == "abcdef" or die "Wrong value";
"abc" x 3 == "abcabcabc" or die "Wrong value";

遞增 (Increment) 和遞減 (Decrement)

遞增和遞減是加減 1 的語法糖,因為我們時常在迴圈及其他情境會用到。可用的運算子如下:

  • ++:遞增
  • --:遞減

以下是實例:

my $n = 3; $n++;
$n == 4 or die "Wrong value";

遞增或遞減是表達式,但會造成變數的狀態改變,因此會有一些誤用的情形,如下例:

my $a = 3;
my $b = 4;

# DON'T DO THIS IN PRODUCTION CODE.
++$a + $b++ == 8 or die "Wrong value";

$a == 4 or die "Wrong value";
$b == 5 or die "Wrong value";

++$a + $b++ 這種經典反例在很多語言都可以看到,雖然要知道這個用法,但最好不要這樣寫。

三元運算子

三元運算子是簡短版的 if ... else ... 敘述,好處是三元運算子為表達式,可以放在其他表達式中。以下是其虛擬碼:

condition ? yes : no

condition 的條件符合時,回傳 yes,反之,回傳 no。以下是實例:

my $a = 4;
my $b = 3;

my $max = $a > $b ? $a : $b;
$max == 4 or die "Wrong value";

本程式的 $a > $b ? $a : $b 會回傳兩者之中較大的值。在本例中,$a 大於 $b,故回傳 $a

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。