運算子 (Operator)

    前言

    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) 型別。我們將於物件導向程式中介紹運算子重載。

    【分享本文】
    Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Yahoo
    【追蹤本站】
    Facebook Facebook Twitter Plurk