Perl 6 中的操作符

操作符


操作符優先級


在像 1 + 2 * 3 這樣的表達式中, 2 * 3 被首先計算, 因為中綴操作符 * 的優先級比 + 的優先級高。下面的表中總結了 Perl 6 中 的優先級級別, 從最牢固到最松散:

A   Level              Examples
N   Terms              42 3.14 "eek" qq["foo"] $x :!verbose @$array
L   方法后綴            .meth .+ .? .* .() .[] .{} .<> .?? .:: .= .^ .:
N   自增                ++ --
R   求冪                **
L   Symbolic unary     ! + - ~ ? | || +^ ~^ ?^ ^
L   乘法                * / % %% +& +< +> ~& ~< ~> ?& div mod gcd lcm
L   加法                + - +| +^ ~| ~^ ?| ?^
L   重復                x xx
X   連結                ~
X   Junctive and       &
X   Junctive or        | ^
L   Named unary        temp let
N   Structural infix   but does <=> leg cmp .. ..^ ^.. ^..^
C   Chaining infix     != == < <= > >= eq ne lt le gt ge ~~ === eqv !eqv
X   Tight and          &&
X   Tight or           || ^^ // min max
R   Conditional        ?? !! ff fff
R   Item assignment    = => += -= **= xx= .=
L   Loose unary        so not
X   Comma operator     , :
X   List infix         Z minmax X X~ X* Xeqv ...
R   List prefix        print push say die map substr ... [+] [*] any Z=
X   Loose and          and andthen
X   Loose or           or xor orelse
X   Sequencer          <==, ==>, <<==, ==>>
N   Terminator         ; {...}, unless, extra ), ], }

下面使用的兩處 ! 符號一般代表任何一對兒擁有相同優先級的操作符, 上表指定的二元操作符的結合性解釋如下(其中 A 代表結合性, associativities ):

A   Assoc   Meaning of $a ! $b ! $c
L   left    ($a ! $b) ! $c
R   right   $a ! ($b ! $c)
N   non     ILLEGAL
C   chain   ($a ! $b) and ($b ! $c)
X   list    infix:<!>($a; $b; $)

對于一元操作符, 這解釋為:

A   Assoc   Meaning of !$a!
L   left    (!$a)!
R   right   !($a!)
N   non     ILLEGAL

下面描述的操作符, 默認假定為 left 結合性。

操作符種類


操作符能出現在相對于 term 的幾個位置處:

+term           prefix         (后綴)
term1 + term2   infix          (中綴)
term++          postfix        (后綴)
(term)          circumfix      (環綴)
term1[term2]    postcircumfix  (后環綴)

每個操作符也可以用作子例程。 這樣的子例程的名字由操作符的種類, 然后后跟一個冒號,再加上一組引號結構, 引號結構中是組成操作符的符號(s):

infix:<+>(1, 2)                           # same as 1 + 2
circumfix:?( )?('a', 'b', 'c')            # same as ('a', 'b', 'c'), 目前編譯錯誤。
circumfix:<[ ]>('a', 'b', 'c').perl.say   # ["a", "b", "c"]

作為一種特殊情況, listop(列表操作符)既能作為 term 又能作為前綴。子例程調用是最常見的列表操作符。其它情況包括元運算中綴操作符 [+]| 1, 2, 3prefix 等 stub 操作符。

定義自定義操作符在 /language/functions#Defining_Operators. 中有涉及。

Term 優先級


Term 怎么翻譯才合適? 我覺得翻譯成 更合適, 表明這是一個名詞。

環綴 < >


引起單詞的結構。以空白隔開內容, 并返回一個單詞的 Parcel。 如果單詞看起來像數字字面量或 Pair 字面量, 那么它會被轉為合適的數字。

say <a b c>[1]  # b

(Rakudo 當前總是返回一塊兒字符串)。

環綴 ( )


分組操作符。

空的分組 () 創建一個空的 Pracel。 非空表達式周圍的圓括號只是構建了表達式, 而沒有額外的語義。

在參數列表中,在參數周圍放上圓括號防止了參數被解釋為具名參數。

multi sub p(:$a!) { say 'named'      }
multi sub p($a)   { say 'positional' }
p a => 1;       # named
p (a => 1);     # positional

環綴 { }


Block 或 散列構造器。

如果{} 里面的內容看起來像一組 pairs 并且沒有 $_ 或其它占位符參數,就返回一個散列, 這個散列由逐項逐項的 pair 組成。

否則就返回一個 Block。

注意,這個結構沒有重新解析內容; 而里面的內容總是被解析為一組句子(例如,像一個 block), 并且如果后面的分析表明它需要被解析成一個散列, 那么 block 就會被執行并強轉為散列。

環綴 [ ]


數組構造器。在列表上下文中返回一個不會展平的 item 化的數組。

方法后綴優先級


后環綴 [ ]


sub postcircumfix:<[ ]>(@container, **@index,
                        :$k, :$v, :$kv, :$p, :$exists, :$delete)

:$k 會創建一個 pair, 它是散列中的一個條目。 鍵是 k, 鍵值為 $kv。 所以, $k 等價于 k => $k

訪問 @container 中的一個或多個元素,即數組索引操作:

my @alphabet = 'a' .. 'z';
say @alphabet[0];                   #-> a
say @alphabet[1];                   #-> b
say @alphabet[*-1];                 #-> z
say @alphabet[100]:exists;          #-> False
say @alphabet[15, 4, 17, 11].join;  #-> perl
say @alphabet[23 .. *].perl;        #-> ("x", "y", "z")

@alphabet[1, 2] = "B", "C";
say @alphabet[0..3].perl            #-> ("a", "B", "C", "d")

查看 Subscripts 獲取關于該操作符行為的更詳細的解釋, 還有怎么在自定義類型中實現對它的支持。

后環綴 { }


sub postcircumfix:<{ }>(%container, **@key,
                        :$k, :$v, :$kv, :$p, :$exists, :$delete)

訪問 %container 的一個或多個元素, 即散列索引操作:

my  %color = kiwi => "green", banana => "yellow", cherry => "red";
say %color{"banana"};               #-> yellow
say %color{"cherry", "kiwi"}.perl;  #-> ("red", "green")
say %color{"strawberry"}:exists;    #-> False

%color{"banana", "lime"} = "yellowish", "green";
%color{"cherry"}:delete;
say %color;  #-> banana => yellowish, kiwi => green, lime => green

查看 后環綴 < >后環綴 ? ? 作為便捷形式, 查看 Subscripts 獲取這個操作符行為的更詳細解釋, 還有怎么在自定義類型中實現對它的支持。

后環綴 < >


后環綴 { } 的簡寫形式, 它會引起它的參數。

my %color = kiwi => "green", banana => "yellow", cherry => "red";
say %color<banana>;             #-> yellow
say %color<cherry kiwi>.perl;   #-> ("red", "green")
say %color<strawberry>:exists;  #-> False

這不是一個真正的操作符, 它僅僅是一個在編譯時把 < > 變成 {} 后環綴操作符的語法糖。

后環綴 ? ?


后環綴 { } 的簡寫形式。它會引起它的參數,并且 ? ? 中能進行變量插值。

my %color = kiwi => "green", banana => "yellow", cherry => "red";
my $fruit = "kiwi";
say %color?cherry $fruit?.perl;   #-> ("red", "green")

這不是一個真正的操作符, 它僅僅是一個在編譯時把 ? ? 變成 {} 后環綴操作符的語法糖。

后環綴 ( )


調用操作符。把調用者當作 Callable 并引用它,它使用圓括號之間的表達式作為參數。

注意,標識符后面直接跟著一對兒圓括號總是被解析為子例程調用。

如果你想要你的對象響應該調用操作符, 你需要實現 CALL-ME 方法。

postfix .


該操作符用于調用一個方法, $invocant.method

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .=


可變的方法調用。 $invocant.=method , 脫去語法糖后就是 $invocant = $invocant.method , 這與 op=. 類似。

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .^


元方法調用。 $invocant.^method$invocant 的元類身上調用方法。脫去語法糖后, 它就是 $invocant.HOW.method($invocant, ...) 。 查看 HOW 獲取更多信息。

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .?


有可能被調用的方法調用。如果有名為 method 的方法, $invocant.?method 就在 $invocant 上調用 method 方法。否則它就返回 Nil。

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .+


$invocant.+method$invocant 身上調用所有叫做 method 的方法, 并返回一個 Parcel 作為結果。 如果沒有找到這個名字的方法, 就會死掉。

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .*


$invocant.*method $invocant身上調用所有叫做method` 的方法, 并返回一個 Parcel 作為結果。 如果沒有找到這個名字的方法,則返回一個空的 Parcel。

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .postfix


大多數情況下, 可以在后綴或后環綴前面放上一個點:

@a[1, 2, 3];
@a.[1, 2, 3]; # Same

這對于視覺清晰或簡潔很有幫助。例如,如果對象的屬性是一個函數,在屬性名后面放置一對兒圓括號會變成方法調用的一部分。 所以要么使用兩對兒圓括號, 要么在圓括號前面放上一個點來阻止方法調用。

class Operation {
    has $.symbol;
    has &.function;
}
my $addition = Operation.new(:symbol<+>, :function{ $^a + $^b });
say $addition.function()(1, 2); # 3

或者

say $addition.function.(1,2); # 3

然而,如果后綴是一個標識符, 那么它會被解釋為一個普通的方法調用。

1.i # No such method 'i' for invocant of type 'Int'

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .:<prefix>


前綴能夠像方法那樣, 使用冒號對兒標記法來調用。例如:

my $a = 1;
say ++$a;     # 2
say $a.:<++>; # 3

技術上講, 這不是一個操作符,而是編譯器中特殊情況下的語法。

postfix .::


一個類限定的方法調用, 用于調用一個定義在父類或 role 中的方法, 甚至在子類中重新定義了之后。

class Bar {
    method baz { 42 }
}

class Foo is Bar {
    method baz { "nope" }
}
say Foo.Bar::baz; # 42

自增優先級


prefix ++


multi sub prefix:<++>($x is rw) is assoc<none>

把它的參數增加 1, 并返回增加后的值。

my $x = 3;
say ++$x;    # 4
say $x;      # 4

它的工作原理是在它的參數身上調用 succ 方法, 這可以讓自定義類型自由地實現它們自己的增量語義。

prefix --


multi sub prefix:<-->($x is rw) is assoc<none>

把它的參數減少 1, 并返回減少后的值。

my $x = 3;
say --$x;       # 2
say $x;         # 2

它的工作原理是在它的參數身上調用 pred 方法, 這可以讓自定義類型自由地實現它們自己的減量語義。

postfix ++


multi sub postfix:<++>($x is rw) is assoc<none>

把它的參數增加 1, 并返回unincremented的那個值。

my $x = 3;
say $x++;       # 3
say $x;         # 4

它的工作原理是在它的參數身上調用 succ 方法, 這可以讓自定義類型自由地實現它們自己的增量語義。

注意這并不一定返回它的參數。 例如,對于未定義的值, 它返回 0:

my $x;
say $x++;       # 0
say $x;         # 1

postfix --


multi sub postfix:<-->($x is rw) is assoc<none>

把它的參數減少 1, 并返回undecremented的那個值。

my $x = 3;
say $x--;       # 3
say $x;         # 2

它的工作原理是在它的參數身上調用 pred 方法, 這可以讓自定義類型自由地實現它們自己的減量語義。

注意這并不一定返回它的參數。 例如,對于未定義的值, 它返回 0:

my $x;
say $x--;       # 0
say $x;         # -1

求冪優先級


infix **


multi sub infix:<**>(Any, Any) returns Numeric:D is assoc<right>

求冪操作符把它的兩個參數都強制轉為 Numeric , 然后計算,右側為冪。

如果 ** 右邊是一個非負整數,并且左側是任意精度類型(Int, FatRat),那么計算不會損失精度。

象形一元操作符的優先級


prefix ?


multi sub prefix:<?>(Mu) returns Bool:D

布爾上下文操作符。

通過在參數身上調用 Bool 方法強制它的參數為 Bool。注意, 這會使 Junctions 失效。

prefix !


multi sub prefix:<!>(Mu) returns Bool:D

否定的布爾上下文操作符。

通過在參數身上調用 Bool 方法強制它的參數為 Bool, 并返回結果的否定值。注意, 這會使 Junctions 失效。

prefix +


multi sub prefix:<+>(Any) returns Numeric:D

Numeric 上下文操作符。

通過在參數身上調用 Numeric 方法強制將參數轉為 Numeric 類型。

prefix -


multi sub prefix:<->(Any) returns Numeric:D

否定的 Numeric 上下文操作符。

通過在參數身上調用 Numeric 方法強制將參數轉為 Numeric 類型, 并返回結果的否定值。

prefix ~


multi sub prefix:<->(Any) returns Str:D

字符串上下文操作符。

通過在參數身上調用 Str 方法強制把參數轉為 Str 類型。

prefix |


將 Capture, Enum, Pair, List, Parcel, EnumMap 和 Hash 展平到參數列表中。

(在 Rakudo 中,這不是作為一個合適的操作符來實現的,而是編譯器中的一種特殊情況, 這意味著它只對參數列表有效,而非在任意代碼中都有效。)

prefix +^


multi sub prefix:<+^>(Any) returns Int:D

Integer bitwise negation

整數按位取反。

將參數強轉為 Int 類型并對結果按位取反, 假設兩者互補。

prefix ?^


multi sub prefix:<?^>(Mu) returns Bool:D

布爾按位取反。

將參數強轉為 Bool, 然后按位反轉,這使它和 prefix:<!> 一樣。

prefix ^


multi sub prefix:<^>(Any) returns Range:D

upto 操作符.

強制把它的參數轉為 Numeric, 生成一個從 0 直到(但是排除) 參數為止的范圍。

say ^5;         # 0..^5
for ^5 { }      # 5 iterations

乘法優先級


infix *


multi sub infix:<*>(Any, Any) returns Numeric:D

把兩邊的參數都強轉為 Numeric 并把它們相乘。 結果是一個更寬的類型。 查看 Numeric 獲取更詳細信息。

infix /


multi sub infix:</>(Any, Any) returns Numeric:D

把兩邊的參數都強制為 Numeric, 并用左邊除以右邊的數。整數相除返回 Rat, 否則返回"更寬類型” 的結果。

infix div


multi sub infix:<div>(Int:D, Int:D) returns Int:D

整除。向下取整。

infix %


multi sub infix:<%>($x, $y) return Numeric:D

模操作符。首先強制為 Numeric。

通常,下面的等式是成立的:

$x % $y == $x - floor($x / $y) * $y

infix %%


multi sub infix:<%%>($a, $b) returns Bool:D

整除操作符, 如果 $a % $b == 0 則返回 True.

infix mod


multi sub infix:<mod>(Int:D $a, Int:D $b) returns Int:D

整數取模操作符。 返回整數取模操作的剩余部分。

infix +&


multi sub infix:<+&>($a, $b) returns Int:D

Numeric 按位 AND。 把兩個參數都強轉為 Int 并執行按位 AND 操作,假定兩者是互補的。

infix +<


multi sub infix:<< +< >>($a, $b) returns Int:D

向左移動整數個位。

infix +>


multi sub infix:<< +> >>($a, $b) returns Int:D

向右移動整數個位。

infix gcd


multi sub infix:<gcd>($a, $b) returns Int:D

強制兩個參數都為 Int 并返回最大公分母(greatest common denominator)。

infix lcm


multi sub infix:<lcm>($a, $b) returns Int:D

強制兩個參數為 Int 并返回最小公倍數(least common multiple)

加法優先級


infix +


multi sub infix:<+>($a, $b) returns Numeric:D

強制兩個參數為 Numeric 并把它們相加。

infix -


multi sub infix:<->($a, $b) returns Numeric:D

強制兩個參數為 Numeric 并用第一個參數減去第二個參數。

infix +|


multi sub infix:<+|>($a, $b) returns Int:D

強制兩個參數為 Int 并執行按位 OR(包括 OR)

infix +^


multi sub infix:<+^>($a, $b) returns Int:D

強制兩個參數為 Int 并執行按位 XOR(不包括 OR)

infix ?|


multi sub infix:<?|>($a, $b) returns Bool:D

強制兩個參數為 Bool 并執行邏輯 OR(不包括 OR)

重復操作符優先級


infix x


proto sub infix:<x>(Any, Any) returns Str:D
multi sub infix:<x>(Any, Any)
multi sub infix:<x>(Str:D, Int:D)

$a 強轉為 Str , 把 $b 強轉為 Int, 并重復字符串 $b 次。 如果 $b <= 0 則返回空字符串。

say 'ab' x 3;       # ababab
say 42 x 3;         # 424242

infix xx


multi sub infix:<xx>($a, $b) returns List:D

返回一組重復的 $a 并計算 $b 次($b 被強轉為 Int)。 如果 $b <= 0 ,則返回一個空列表。

每次重復都會計算左側的值, 所以

[1, 2] xx 5

返回 5 個不同的數組(但是每次都是相同的內容)并且

rand xx 3

返回 3 個獨立的偽隨機數。右側可以是 *, 這時會返回一個惰性的,無限的列表。

連結


infix ~


proto sub infix:<~>(Any, Any) returns Str:D
multi sub infix:<~>(Any,   Any)
multi sub infix:<~>(Str:D, Str:D)

強制兩個參數為 Str 并連結它們。

say 'ab' ~ 'c';     # abc

Junctive AND (all) 優先級


infix &


multi sub infix:<&>($a, $b) returns Junction:D is assoc<list>

用它的參數創建一個 all Junction。查看 Junctions 獲取更多詳情。

Junctive OR (any) Precedence


infix |


multi sub infix:<|>($a, $b) returns Junction:D is assoc<list>

用它的參數創建一個 any Junction。查看 Junctions 獲取更多詳情。

infix ^


multi sub infix:<^>($a, $b) returns Junction:D is assoc<list>

用它的參數創建一個 one Junction。查看 Junctions 獲取更多詳情。

Named Unary Precedence


prefix temp


sub prefix:<temp>(Mu $a is rw)

temporizes 傳入的變量作為參數, 這意味著退出作用域后它被重置為舊值。(這和 Perl 5 中的 local 操作符類似, 除了 temp 不重置值之外。)

prefix let


sub prefix:<let>(Mu $a is rw)

假定重置:如果通過異?;?fail()退出當前作用域, 舊值就會被恢復。

Nonchaining Binary Precedence


infix does


sub infix:<does>(Mu $obj, Mu $role) is assoc<none>

在運行時把 $role 混合進 $obj 中。 要求 $obj 是可變的。

參數 $role 不一定要求是一個 role, 它可以表現的像是一個 role, 例如枚舉值。

infix but


sub infix:<but>(Mu $obj, Mu $role) is assoc<none>

$role 混合進 $obj 并創建一個 $obj 的副本。因為 $obj 是不能修改的,但是能使用 mixins 用于創建不可變值。

參數 $role 不一定要求是一個 role, 它可以表現的像是一個 role, 例如枚舉值。

infix cmp


proto sub infix:<cmp>(Any, Any) returns Order:D is assoc<none>
multi sub infix:<cmp>(Any,       Any)
multi sub infix:<cmp>(Real:D,    Real:D)
multi sub infix:<cmp>(Str:D,     Str:D)
multi sub infix:<cmp>(Enum:D,    Enum:D)
multi sub infix:<cmp>(Version:D, Version:D)

一般的, “智能的” 三路比較器。

比較字符串時使用字符串語義, 比較數字時使用數字語義, 比較 Pair 對象時, 先比較鍵, 再比較值,等等。

if $a eqv $b, then $a cmp $b always returns Order::Same.
say (a => 3) cmp (a => 4);      # Less
say 4        cmp 4.0;           # Same
say 'b'      cmp 'a';           # More

infix leg


proto sub infix:<leg>($a, $b) returns Order:D is assoc<none>
multi sub infix:<leg>(Any,   Any)
multi sub infix:<leg>(Str:D, Str:D)

字符串三路比較器。 leg 是 less, equal 還有 greater 的簡寫形式?

把兩個參數都強轉為 Str , 然后按照字母次序比較。

say 'a' leg 'b';        Less
say 'a' leg 'a';        Same
say 'b' leg 'a';        More

infix <=>


multi sub infix:?<=>?($a, $b) returns Order:D is assoc<none>

Numeric 三路比較器。

把兩個參數強轉為 Real, 并執行數值比較。

infix ..


multi sub infix:<..>($a, $b) returns Range:D is assoc<none>

由參數創建一個 Range。

infix ..^


multi sub infix:<..^>($a, $b) returns Range:D is assoc<none>

由參數創建一個 Range, 不包含末端。

infix ^..


multi sub infix:<^..>($a, $b) returns Range:D is assoc<none>

由參數創建一個 Range, 不包含開始端點。

infix ..


multi sub infix:<^..^>($a, $b) returns Range:D is assoc<none>

由參數創建一個 Range, 不包含開端和末端。

Chaining Binary Precedence


infix ==


proto sub infix:<==>($, $) returns Bool:D is assoc:<chain>
multi sub infix:<==>(Any, Any)
multi sub infix:<==>(Int:D, Int:D)
multi sub infix:<==>(Num:D, Num:D)
multi sub infix:<==>(Rational:D, Rational:D)
multi sub infix:<==>(Real:D, Real:D)
multi sub infix:<==>(Complex:D, Complex:D)
multi sub infix:<==>(Numeric:D, Numeric:D)

強轉兩個參數為 Numeric(如果必要), 并?返回 True 如果它們相等。

infix !=


proto sub infix:<!=>(Mu, Mu) returns Bool:D is assoc<chain>

強轉兩個參數為 Numeric(如果必要), 并?返回 True 如果它們不相等。

infix <


proto sub infix:?<?(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:?<?(Int:D, Int:D)
multi sub infix:?<?(Num:D, Num:D)
multi sub infix:?<?(Real:D, Real:D)

強轉兩個參數為 Real (如果必要), 并返回 True 如果第一個參數小于第二個參數。

infix <=


proto sub infix:?<=?(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:?<=?(Int:D, Int:D)
multi sub infix:?<=?(Num:D, Num:D)
multi sub infix:?<=?(Real:D, Real:D)

強轉兩個參數為 Real (如果必要), 并返回 True 如果第一個參數小于第二個參數。

infix >


proto sub infix:?>?(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:?>?(Int:D, Int:D)
multi sub infix:?>?(Num:D, Num:D)
multi sub infix:?>?(Real:D, Real:D)

強轉兩個參數為 Real (如果必要), 并返回 True 如果第一個參數大于第二個參數。

infix >=


proto sub infix:?>=?(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:?>=?(Int:D, Int:D)
multi sub infix:?>=?(Num:D, Num:D)
multi sub infix:?>=?(Real:D, Real:D)

強轉兩個參數為 Real (如果必要), 并返回 True 如果第一個參數大于或等于第二個參數。

infix eq


proto sub infix:<eq>(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:<eq>(Any,   Any)
multi sub infix:<eq>(Str:D, Str:D)

強轉兩個參數為 Str(如果必要), 并返回 True 如果第一個參數等于第二個參數。

助記法: equal

infix ne


proto sub infix:<ne>(Mu, Mu) returns Bool:D is assoc<chain>
multi sub infix:<ne>(Mu,    Mu)
multi sub infix:<ne>(Str:D, Str:D)

強轉兩個參數為 Str(如果必要), 并返回 False 如果第一個參數等于第二個參數。

助記法: not equal

infix gt


proto sub infix:<gt>(Mu, Mu) returns Bool:D is assoc<chain>
multi sub infix:<gt>(Mu,    Mu)
multi sub infix:<gt>(Str:D, Str:D)

強轉兩個參數為 Str(如果必要), 并返回 True 如果第一個參數大于第二個參數。

助記法: greater than

infix ge


proto sub infix:<ge>(Mu, Mu) returns Bool:D is assoc<chain>
multi sub infix:<ge>(Mu,    Mu)
multi sub infix:<ge>(Str:D, Str:D)

強轉兩個參數為 Str(如果必要), 并返回 True 如果第一個參數大于第二個參數。

助記法: greater or equal

infix lt


proto sub infix:<lt>(Mu, Mu) returns Bool:D is assoc<chain>
multi sub infix:<lt>(Mu,    Mu)
multi sub infix:<lt>(Str:D, Str:D)

強轉兩個參數為 Str(如果必要), 并返回 True 如果第一個參數小于第二個參數。

助記法: less than

infix le


proto sub infix:<le>(Mu, Mu) returns Bool:D is assoc<chain>
multi sub infix:<le>(Mu,    Mu)
multi sub infix:<le>(Str:D, Str:D)

強轉兩個參數為 Str(如果必要), 并返回 True 如果第一個參數小于或等于第二個參數。

助記法: less or equal

infix before


proto sub infix:<before>(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:<before>(Any,       Any)
multi sub infix:<before>(Real:D,    Real:D)
multi sub infix:<before>(Str:D,     Str:D)
multi sub infix:<before>(Enum:D,    Enum:D)
multi sub infix:<before>(Version:D, Version:D)

一般的排序, 使用?和 cmp 相同的語義。 如果第一個參數小于第二個參數則返回 True。

infix after


proto sub infix:<after>(Any, Any) returns Bool:D is assoc<chain>
multi sub infix:<after>(Any,       Any)
multi sub infix:<after>(Real:D,    Real:D)
multi sub infix:<after>(Str:D,     Str:D)
multi sub infix:<after>(Enum:D,    Enum:D)
multi sub infix:<after>(Version:D, Version:D)

一般的排序, 使用?和 cmp 相同的語義。 如果第一個參數大于第二個參數則返回 True。

infix eqv


proto sub infix:<eqv>(Any, Any) returns Bool:D is assoc<chain>
proto sub infix:<eqv>(Any, Any)

等值操作符。如果兩個參數在結構上相同就返回 True。例如, 相同類型(并且遞歸)包含相同的值。

say [1, 2, 3] eqv [1, 2, 3];        # True
say Any eqv Any;                    # True
say 1 eqv 2;                        # False
say 1 eqv 1.0;                      # False

對于任意對象使用默認的 eqv 操作是不可能的。例如, eqv 不認為同一對象的兩個實例在結構上是相等的:

class A {
    has $.a;
}

say A.new(a => 5) eqv A.new(a => 5);  #=> False

要得到這個類的對象相等(eqv)語義, 需要實現一個合適的中綴 eqv 操作符:

class A {
    has $.a;
}

multi infix:<eqv>(A $l, A $r) { $l.a eqv $r.a }
say A.new(a => 5) eqv A.new(a => 5);  #=> True

infix ===


proto sub infix:<===>(Any, Any) returns Bool:D is assoc<chain>
proto sub infix:<===>(Any, Any)

值相等。如果兩個參數都是同一個對象則返回 True。

class A { };

my $a = A.new;
say $a === $a;              # True
say A.new === A.new;        # False
say A === A;                # True

對于值的類型, === 表現的和 eqv 一樣:

say 'a' === 'a';            # True
say 'a' === 'b';            # False

# different types
say 1 === 1.0;              # False

=== 使用 WHICH 方法來獲取對象相等, 所以所有的值類型必須重寫方法 WHICH

infix =:=


proto sub infix:<=:=>(Mu \a, Mu \b) returns Bool:D is assoc<chain>
multi sub infix:<=:=>(Mu \a, Mu \b)

容器相等。返回 True 如果兩個參數都綁定到同一個容器上。 如果它返回 True, 那通常意味著修改一個參數也會同時修改另外一個。

my ($a, $b) = (1, 3);
say $a =:= $b;      # False
$b = 2;
say $a;             # 1
$b := $a;
say $a =:= $b;      # True
$a = 5;
say $b;             # 5

infix ~~


智能匹配操作符。把左側參數起別名為 $_ , 然后計算右側的值, 并在它身上調用 .ACCEPTS($_) 。 匹配的語義由右側操作數的類型決定。

這兒有一個內建智能匹配函數的摘要:

右側      比較語義
Mu:U      類型檢查
Str       字符串相等
Numeric   數值相等
Regex     正則匹配
Callable  調用的布爾結果
Any:D     對象相等

Tight AND Precedence


infix &&


在布爾上下文中返回第一個求值為 False 的參數, 否則返回最后一個參數。

注意這是短路操作符,如果其中的一個參數計算為 false 值, 那么該參數右側的值絕不會被計算。

sub a { 1 }
sub b { 0 }
sub c { die "never called" };
say a() && b() && c();      # 0

Tight OR Precedence


infix ||


在布爾上下文中返回第一個求值為 True 的參數, 否則返回最后一個參數。

注意這是短路操作符,如果其中的一個參數計算為 true 值, 那么該參數右側的值絕不會被計算。

sub a { 0 }
sub b { 1 }
sub c { die "never called" };
say a() || b() || c();      # 1

infix ^^


返回第一個值為 true 的參數如果只有一個的話, 否則返回 Nil。只要找到兩個值為 true 的參數就發生短路。

say 0 ^^ 42;                # 42
say 0 ^^ 42 ^^ 1 ^^ die 8;  # (empty line)

注意, 這個操作符的語義可能不是你假想的那樣: infix ^^ 翻到它找到的第一個 true 值, 找到第二個 true 值后永遠地反轉為 Nil 值, 不管還有多少 true 值。(換句話說,它的語義是”找到一個真值”, 而不是布爾起奇偶校驗語義)

infix //


Defined-or 操作符。返回第一個定義了的操作數, 否則返回最后一個操作數。短路操作符。

say Any // 0 // 42;         # 0

infix min


返回參數的最小值。語義由 cmp 語義決定。

$foo min= 0  # read as: $foo decreases to 0

infix max


返回參數的最大值。

$foo max= 0  # read as: $foo increases to 0

Conditional Operator Precedence


infix ?? !!


三目操作符, 條件操作符。

$condition ?? $true !! $false 計算并返回 $true 表達式,如果 $condition 為真的話。 否則計算并返回 $false 分支。

infix ff


sub infix:<ff>(Mu $a, Mu $b)

Flipflop operator. 觸發器操作符。

把兩個參數都跟 $_ 進行比較(即,$_ ~~ $a$_ ~~ $b)。求值為 False 直到左側的智能匹配為真, 這時,它求值為真, 直到右側的智能匹配為真。

實際上,左邊的參數是"開始”條件, 右側的參數是”停止” 條件。 這種結構一般用于收集只在特定區域的行。 例如:

my $excerpt = q:to/END/;
Here's some unimportant text.
=begin code
    This code block is what we're after.
    We'll use 'ff' to get it.
=end code
More unimportant text.
END

my @codelines = gather for $excerpt.lines {
    take $_ if "=begin code" ff "=end code"
}

# this will print four lines,
# starting with "=begin code" and ending with "=end code"
say @codelines.join("\n");

匹配開始條件之后,操作符會繼續將停止條件與 $_ 進行匹配, 如果成功就做相應地表現。在這個例子中, 只有第一個元素被打印了:

for <AB C D B E F> {
    say $_ if /A/ ff /B/;  # prints only "AB"
}

如果你想測試開始條件, 并且沒有結束條件, * 能用作 “停止” 條件。

for <A B C D E> {
    say $_ if /C/ ff *; # prints C, D, and E
}

對于 sed-like 版本, 在開始條件匹配成功之后,它不會使用停止條件與 $_ 進行匹配。

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix ^ff


sub infix:<^ff>(Mu $a, Mu $b)

像 ff 那樣工作,除了它不會在條目匹配開始條件時返回真。(包括匹配停止條件的條目)

一個比較:

my @list = <A B C>;
say $_ if /A/ ff /C/ for @list;  # prints A, B, and C
say $_ if /A/ ^ff /C/ for @list; # prints B and C

sed-like 版本 可以在 ^fff 中找到.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix ff^


sub infix:<ff^>(Mu $a, Mu $b)

像 ff 那樣工作,除了它不會在條目匹配停止條件時返回真。(包括第一次匹配開始條件的條目)

my @list = <A B C>;
say $_ if /A/ ff /C/ for @list;  # prints A, B, and C
say $_ if /A/ ff^ /C/ for @list; # prints A and B

sed-like 版本 可以在 fff^ 中找到.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix ff


sub infix:<^ff^>(Mu $a, Mu $b)

像 ff 那樣工作,除了它不會在條目匹配停止條件時返回真, 也不會在條目匹配開始時返回真。(或者兩者)

my @list = <A B C>;
say $_ if /A/ ff /C/ for @list;  # prints A, B, and C
say $_ if /A/ ^ff^ /C/ for @list; # prints B

sed-like 版本 可以在 fff 中找到.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix fff


sub infix:<fff>(Mu $a, Mu $b)

執行 sed-like 那樣的 flipflop 操作,在其中,它返回 False 直到左側的參數與 $_ 智能匹配, 并且在那之后返回 True 直到右側的參數和 $_ 智能匹配。

像 ff 那樣工作, 除了它每次調用只嘗試一個參數之外。即, 如果 $_ 和左側的參數智能匹配, fff 隨后不會嘗試將同一個 $_ 和右側的參數進行匹配。

for <AB C D B E F> {
    say $_ if /A/ fff /B/;  # Prints "AB", "C", "D", and "B"
}

對于 non-sed-like 版本, 查看 ff.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix ^fff


sub infix:<^fff>(Mu $a, Mu $b)

像 fff那樣, 除了它對于左側的匹配不返回真之外。

my @list = <A B C>;
say $_ if /A/ fff /C/ for @list;  # prints A, B, and C
say $_ if /A/ ^fff /C/ for @list; # prints B and C

對于 non-sed 版本, 查看 ^ff.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix fff^


sub infix:<fff^>(Mu $a, Mu $b)

像 fff 那樣, 除了它對于右側的匹配不返回真之外。

my @list = <A B C>;
say $_ if /A/ fff /C/ for @list;  # prints A, B, and C
say $_ if /A/ fff^ /C/ for @list; # prints A and B

對于 non-sed 版本, 查看 ff^.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

infix fff


sub infix:<^fff^>(Mu $a, Mu $b)

像 fff 那樣, 除了它對于左側和右側的匹配都不返回真之外。

my @list = <A B C>;
say $_ if /A/ fff /C/ for @list;  # prints A, B, and C
say $_ if /A/ ^fff^ /C/ for @list; # prints B

對于 non-sed 版本, 查看 ^ff^.

這個操作符不能被重載, 因為它被編譯器特殊處理過。

Item Assignment Precedence


infix =


sub infix:<=>(Mu $a is rw, Mu $b)

Item 賦值.

把 = 號右側的值放入左側的容器中。 它真正的語義是由左側的容器類型決定的。

(注意 item 賦值和列表賦值的優先級級別不同, 并且等號左側的語法決定了等號是被解析為 item 賦值還是列表賦值操作符)。

infix =>


sub infix:?=>?($key, Mu $value) returns Pair:D

Pair 構造器.

使用左側值作為鍵, 右側值作為值,構造一個 Pair 對象。

注意 => 操作符是語法上的特例,在這個結構中, 它允許左側是一個未被引起的標識符。

my $p = a => 1;
say $p.key;         # a
say $p.value;       # 1

在參數列表中,在 => 左側使用未被引起的標識符構建的 Pair 會被解釋為一個具名參數。

查看 Terms 語言文檔了解更多創建 Pair 對象的方式。

Loose Unary Precedence


prefix not


multi sub prefix:<not>(Mu $x) returns Bool:D

在布爾上下文中計算它的參數(因此使 Junctions 失效), 并返回否定的結果。

prefix so


multi sub prefix:<so>(Mu $x) returns Bool:D

在布爾上下文中計算它的參數(因此使 Junctions 失效), 并返回結果。

逗號操作符優先級


infix ,


sub infix:<,>(*@a) is assoc<list> returns Parcel:D

從它的參數宏構建一個 Parcel。也在語法構成上用作函數用的參數的分隔符。

infix :


就像中綴操作符 , 那樣, : 用作參數分隔符, 并把它左側的參數標記為調用者。

那會把函數調用轉為方法調用。

substr('abc': 1);       # same as 'abc'.substr(1)

Infix : 只允許出現在非方法調用的第一個參數后面。 在其它位置它會是語法錯誤。

List Infix Precedence


infix Z


sub infix:<Z>(**@lists) returns List:D is assoc<chain>

Zip operator.

Z 像一個拉鏈那樣把列表插入進來, 只要第一個輸入列表耗盡就停止:

say (1, 2 Z <a b c> Z <+ ->).perl;  # ((1, "a", "+"), (2, "b", "-")).list

Z 操作符也作為元操作符存在, 此時內部的 parcels 被應用了元操作符的列表替換:

say 100, 200 Z+ 42, 23;             # 142, 223
say 1..3 Z~ <a b c> Z~ 'x' xx 3;    # 1ax 2bx 3cx

infix X


sub infix:<X>(**@lists) returns List:D is assoc<chain>

從所有列表創建一個外積。最右邊的元素變化得最迅速。

1..3 X <a b c> X 9

# produces   (1, 'a', 9), (1, 'b', 9), (1, 'c', 9),
         (2, 'a', 9), (2, 'b', 9), (2, 'c', 9),
         (3, 'a', 9), (3, 'b', 9), (3, 'c', 9)

X 操作符也可以作為元操作符, 此時內部的 parcels 被應用了元操作符的列表的值替換:

1..3 X~ <a b c> X~ 9

# produces   '1a9', '1b9', '1c9',

         '2a9', '2b9', '2c9',
         '3a9', '3b9', '3c9'

infix ...


multi sub infix:<...>(**@) is assoc<list>
multi sub infix:<...^>(**@) is assoc<list>

序列操作符是一個用于產生惰性列表的普通操作符。

它可以有一個初始元素和一個生成器在 的?左側, 在右側是一個端點。

序列操作符會使用盡可能多的參數來調用生成器。參數會從初始元素和已生成元素中獲取。

默認的生成器是 *.succ*.pred , 取決于末端怎么比較:

say 1 ... 4;        # 1 2 3 4
say 4 ... 1;        # 4 3 2 1
say 'a' ... 'e';    # a b c d e
say 'e' ... 'a';    # e d c b a

* (Whatever) 末端生成一個無限序列,使用的是默認的生成器 *.succ

say (1 ... *)[^5];  # 1 2 3 4 5

自定義生成器是在 操作符之前的最后一個參數。下面這個自定義生成器接收兩個參數, 生成了斐波納契數。

say (1, 1, -> $a, $b { $a + $b } ... *)[^8];    # 1 1 2 3 5 8 13 21
# same but shorter
say (1, 1, *+* ... *)[^8];                      # 1 1 2 3 5 8 13 21

當然自定義生成器也能只接收一個參數。

say 5, { $_ * 2 } ... 40;                       # 5 10 20 40

生成器的參數個數至少要和初始元素的個數一樣多。

如果沒有生成器,并且有不止一個初始元素,所有的初始元素都是數值,那么序列操作符會嘗試推導出生成器。它知道數學和幾何序列。

say 2, 4, 6 ... 12;     # 2 4 6 8 10 12
say 1, 2, 4 ... 32;     # 1 2 4 8 16 32

如果末端不是 *, 它會和每個生成的元素進行智能匹配,當智能匹配成功的時候序列就被終止。對于 ... 操作符, 會包含最后一個元素, 對于 ...^ 操作符,會排除最后的那個元素。

這允許你這樣寫:

say 1, 1, *+* ...^ *>= 100;

來生成所有直到 100 但不包括 100 的斐波納契數。

... 操作符還會把初始值看作”已生成的元素”,所以它們也會對末端進行檢查:

my $end = 4;
say 1, 2, 4, 8, 16 ... $end;
# outputs 1 2 4

List Prefix Precedence


infix =


列表賦值。 它真正的語義是由左側的容器類型決定的。查看 Array 和 Hash 獲取普通案例。

item 賦值和列表賦值的優先級級別不同, 并且等號左側的語法決定了等號是被解析為 item 賦值還是列表賦值操作符。

infix :=


綁定。 而 $x = $y 是把 $y 中的值放到 $x 里面, $x := $y 會讓 $x$y 引用同一個值。

my $a = 42;
my $b = $a;
$b++;
say $a;

這會輸出 42, 因為 $a 和 $b 都包含了數字 42, 但是容器是不同的。

my $a = 42;
my $b := $a;
$b++;
say $a;

這會打印 43, 因為 $b$a 都代表著同一個對象。

infix ::=


只讀綁定. 查看 infix :=.

listop ...


這是yada, yada, yada 操作符 或 stub 操作符。如果它在子例程或類型中是唯一的語句,它會把子例程或類型標記為 stub(這在預聲明類型和組成 roles 上下文中是有意義的)

如果 ... 語句被執行了, 它會調用 &fail , 伴隨著默認的消息 stub 代碼的執行。

listop !!!


如果它在子例程或類型中是唯一的語句,它會把子例程或類型標記為 stub(這在預聲明類型和組成 roles 上下文中是有意義的)

如果 !!! 語句被執行了, 它會調用 &die , 伴隨著默認的消息 stub 代碼的執行。

listop ???


如果它在子例程或類型中是唯一的語句,它會把子例程或類型標記為 stub(這在預聲明類型和組成 roles 上下文中是有意義的)

如果 ??? 語句被執行了, 它會調用 &warn , 伴隨著默認的消息 stub 代碼的執行。

Loose AND precedence


infix and


和中綴操作符 && 一樣,除了優先級更寬松。

在布爾上下文中返回第一個求值為 False 的操作數, 否則返回最后一個操作數。短路操作符。

infix andthen


返回第一個未定義的參數,否則返回最后一個參數。短路操作符。左側的結果被綁定到 $_ 身上, 在右側中使用, 或者作為參數被傳遞,如果右側是一個 block 或 pointy block.

Loose OR Precedence


infix or


和中綴操作符 || 一樣,除了優先級更寬松。

在布爾上下文中返回第一個求值為 True 的參數, 否則返回最后一個參數。短路操作符。

infix orelse


和中綴操作符 // 一樣,除了優先級更寬松之外。

返回第一個定義過的參數, 否則返回最后一個參數。短路操作符。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 操作符優先級 S03-operators/arith.t lines 46–342 S03-operators/p...
    焉知非魚閱讀 1,120評論 0 0
  • 范圍和范圍迭代器語法 .. 范圍操作符有各種在兩端帶有 ^符號的變體以表明把那個端點排除在范圍之外。 它總會產生一...
    焉知非魚閱讀 881評論 0 0
  • infix:<...>, 序列操作符. 作為一個中綴操作符, ... 操作符的左右兩側都有一個列表,并且為了產生想...
    焉知非魚閱讀 745評論 0 1
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,915評論 18 139
  • 還有一周就要開學了,重回校園時,想讓同學們眼前一亮? 可慵懶了一個寒假,不僅體重飆升,智商、睡眠、品味等等,各種指...
    腳猾的狐貍閱讀 1,152評論 1 16