美思 [Raku] 程式設計教學:運算子 (Operator)

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

Raku 的運算子較多,甚至已經到過多的程度;有些較少見的運算子,其實很難記憶。本文不會列出所有的運算子,僅列出常見的運算子。

運算子的種類

根據運算子的位置,分為以下五種:

  • Prefix,例:-3
  • Infix,例:3 + 2
  • Postfix,例:$a++
  • Circumfix,例:<foo bar baz> (字串串列)
  • Postcircumfix,例:@arr[0] (陣列取索引)

平常不需死記這些分類,但了解這個概念對於實作運算子重載 (operator overloading) 會有幫助,我們將於後文說明。

代數運算子

  • +:相加
  • -:相減
  • *:相乘
  • /:相除,未整除得小數
  • div:整數相除
  • %:取餘數,可用於有理數
  • mod:整數取餘數
  • **:指數
  • gcd:取最大公約數
  • lcm:最最小公倍數

以下為實例:

3 + 2 == 5 or die "Wrong value";
3 - 2 == 1 or die "Wrong value";
3 * 2 == 6 or die "Wrong value";
3 / 2 == 1.5 or die "Wrong value";
3 div 2 == 1 or die "Wrong value";
3.77 % 0.1 == 0.07 or die "Wrong value";
3 mod 2 == 1 or die "Wrong value";
3 ** 2 == 9 or die "Wrong value";
60 gcd 35 == 5 or die "Wrong value";
30 lcm 45 == 90 or die "Wrong value";

遞增遞減運算子

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

遞增/減放在變數前後的效果略有不同,但刻意操作這種效果不是好習慣,建議將這類運算子分開獨立的一行撰寫。

二元運算子

二元運算子用於二進位數運算。包括以下運算子:

  • +&:bitwise AND
  • +|:bitwise OR
  • +^:bitwise XOR
  • +<:左移
  • +>:右移

以下是實例:

constant $READ = 4;
constant $WRITE = 2;
constant $EXEC = 1;

$READ +^ $WRITE == 6 or die "Wrong priviledge";
$READ +^ $EXEC == 5 or die "Wrong priviledge";
$READ +^ $WRITE +^ $EXEC == 7 or die "Wrong priviledge";

二元運算較不直覺,但會比代數運算快。當速度是重要考量時,可以試著使用二元運算。

比較運算子

要注意的是,Raku 有兩套比較運算子,分別用於數字和字串的比較。

  • 比較數字
    • ==:相等
    • !=:不相等
    • >:大於
    • >=:大於等於
    • <:小於
    • <=:小於等於
  • 比較字串
    • eq:相等
    • ne:不相等
    • gt:大於
    • ge:大於等於
    • lt:小於
    • le:小於等於

記憶的方式是符號比符號,文字比文字。

以下是實例:

3 == 3 or die "Wrong condition";
3 != 2 or die "Wrong condition";
3 > 2 or die "Wrong condition";
3 >= 2 or die "Wrong condition";
3 < 5 or die "Wrong condition";
3 <= 5 or die "Wrong condition";

"Perl" eq "Perl" or die "Wrong condition";
"Perl" ne "Ruby" or die "Wrong condition";
"Perl" gt "C++" or die "Wrong condition";
"Perl" ge "C++" or die "Wrong condition";
"Perl" lt "Ruby" or die "Wrong condition";
"Perl" le "Ruby" or die "Wrong condition";

除了以上比較運算子,還有以下幾種相等運算子:

  • ~~:智能相等運算子,會根據兩邊的值自動比對是否相等
  • eqv:相等運算子,檢查兩邊的值型別相等且值相等
  • ===:物件相等運算子,對基本型別,同於 eqv,對物件來說,要相同物件才會相等
  • =~=:浮點數相等運算子,當浮點數誤差夠小時相等,預設誤差值為 10 的 -15 次方

另外還有數種三元運算子:

  • cmp:智能三元運算子,會根據兩邊的值自動比對
  • <=>:數字三元運算子,會將兩邊的值轉為 Real 型別
  • leg:字串三元運算子,會將兩邊的值轉為字串後比較 ( 註:leg 是 less、equal、greater 的縮寫 )

以下是實例:

(3 cmp 5) ~~ Less or die "Wrong condition";
("Perl" cmp "Perl") ~~ Same or die "Wrong condition";
("Ruby" cmp "Perl") ~~ More or die "Wrong condition";

另外還提供比較順序的運算子,可用於多種型別:

  • before
  • after

以下是實例:

(10 before 2) == False or die "Wrong logic";
(10 after 2) == True or die "Wrong logic";

("Perl" before "Ruby") == True or die "Wrong logic";
("Perl" after "Ruby") == False or die "Wrong logic";

筆者以為 Raku 的比較運算子種類過多。如果無法全部記起來也沒關係,先記比較基本的比較運算子即可。

邏輯運算子

要注意的是,Raku 有兩套邏輯運算子,兩者優先度有所不同。

  • 低優先度
    • and:且
    • or:或
    • not:否定
  • 高優先度
    • &&:且
    • ||:或
    • !:否定

以下是實例:

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

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

(!True) == False or die "Wrong logic";
(!False) == True or die "Wrong logic";

Raku 的邏輯運算子有兩種優先度,比主流程式語言複雜些。如果無法記住運算子的優先度,用括號來改變運算子優先度即可,不需強記運算子優先度。

布林轉換運算子

布林轉換運算子會將值轉為布林值,可用於條件判斷中。

  • 前綴的 ?:較高優先度
  • 前綴的 so:較低優先度
# Falsy.
?0 == False or die "Wrong state";   # Zero.
?0.0 == False or die "Wrong state"; # Zero (as float).
?"" == False or die "Wrong state";  # Empty string.
?() == False or die "Wrong state";  # Empty list.
?{} == False or die "Wrong state";  # Empty hash.
?Nil == False or die "Wrong state"; # Nil
my $v; ?$v == False or die "Wrong state"; # Undefined variable.

# Truthy: all non-falsey values.
?1 or die "Wrong state";
?1.0 or die "Wrong state";
?"Hello World" or die "Wrong state";
?(1, 2, 3) or die "Wrong state";
?{"one" => "eins", "two" => "zwei", "three" => "drei"} or die "Wrong state";
my $u = 99; ?$u or die "Wrong state";

使用本運算子的要點在於知道那些值為 falsy,即會判定為 False 的值,例子如下:

  • 未定義的變數
  • Nil
  • 0 (整數零)
  • 0.0 (有理數零)
  • "" (空字串)
  • () (空串列)
  • {} (空雜湊)

其他的值則為 truthy,即會判定為 True 的值。

字串運算子

  • x:字串重覆
  • 二元 ~:字串相接
  • 前綴 ~:將值轉為字串

以下是實例:

"Hi" x 3 eq "HiHiHi" or die "Wrong string";
("Hello " ~ "World") eq "Hello World" or die "Wrong string";

範圍運算子

根據不同情境,有以下四種範園運算子:

  • ..:含頭尾
  • ..^:含頭不含尾
  • ^..:不含頭含尾
  • ^..^:不含頭不含尾

使用範園運算子時,要注意是否包含頭尾值。

見以下實例:

1 .. 5 ~~ (1, 2, 3, 4, 5) or die "Unequal list";
1 ..^ 5 ~~ (1, 2, 3, 4) or die "Unequal list";
1 ^.. 5 ~~ (2, 3, 4, 5) or die "Unequal list";
1 ^..^ 5 ~~ (2, 3, 4) or die "Unequal list";

運算子優先順序

Raku 的運算子優先順序很複雜,但不需強記,因為

  • 數學相關的運算子其優先順序和數學知識相同
  • 用括號可改變運算子的優先順序

運算子重載

Raku 支援運算子重載 (operator overloading),除了內建型別外,我們也可以為自訂型別自訂相關的運算子操作,這些自訂型別就可以如同內建型別般操作,例如:向量 (vector) 或矩陣 (matrix) 型別。我們將於物件導向程式中介紹運算子重載。

關於作者

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

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