参见 创建运算符,了解如何定义新的运算符。

运算符优先级§

Raku 运算符的优先级和结合性决定了表达式中操作数的求值顺序。

当两个不同优先级的运算符作用于同一个操作数时,优先级较高的运算符对应的子表达式将首先被求值。例如,在表达式 1 + 2 * 3 中,二元 + 运算符(加法)和二元 * 运算符(乘法)都作用于操作数 2。由于 * 运算符的优先级高于 + 运算符,因此子表达式 2 * 3 将首先被求值。因此,整个表达式的结果为 7 而不是 9

除了“优先级”之外,还可以说“绑定”:优先级较高的运算符被称为与相关操作数有更紧密的绑定,而优先级较低的运算符被称为与相关操作数有更松散的绑定。在实践中,您也可能会遇到术语的混合,例如,运算符具有更紧密或更松散的优先级的说法。

下表总结了 Raku 提供的优先级级别,按优先级从高到低列出。对于每个优先级级别,该表还指示分配给该级别的运算符的结合性(将在下面进一步讨论),并列出该优先级级别的一些示例运算符。

优先级级别结合性示例
术语¹42 3.14 "eek" qq["foo"] $x :!verbose @$array rand time now ∅
方法调用.meth .+ .? .* .() .[] .{} .<> .«» .:: .= .^ .: i
自动递增++ --
指数**
符号一元! + - ~ ? | || +^ ~^ ?^ ^ //
点式中缀¹.= .
乘法* × / ÷ % %% +& +< +> ~& ~< ~> ?& div mod gcd lcm
加法+ - − +| +^ ~| ~^ ?| ?^
复制x xx
连接列表~ o ∘
连接与列表& (&) (.) ∩ ⊍
连接或列表| ^ (|) (^) (+) (-) ∪ ⊖ ⊎ ∖
命名一元¹temp let
结构but does <=> leg unicmp cmp coll .. ..^ ^.. ^..^
链式!= ≠ == ⩵ < <= ≤ > >= ≥ eq ne lt le gt ge ~~ === ⩶ eqv !eqv =~= ≅ (elem) (cont) (<) (>) (<=) (>=) (<+) (>+) (==) ∈ ∊ ∉ ∋ ∍ ∌ ≡ ≢ ⊂ ⊄ ⊃ ⊅ ⊆ ⊈ ⊇ ⊉ ≼ ≽
紧密与列表&&
紧密或列表|| ^^ // min max
条件¹?? !! ff ff^ ^ff ^ff^ fff fff^ ^fff ^fff^
项目赋值=² => += -= **= xx=
松散一元so not
逗号列表, :
列表中缀列表Z minmax X X~ X* Xeqv ... … ...^ …^ ^... ^… ^...^ ^…^
列表前缀=³ ??? !!! ... [+] [*] Z=
松散与列表and andthen notandthen
松散或列表or xor orelse
排序器¹列表<== ==> <<== ==>>
终止符¹; {...} unless extra ) ] }

注释

  • 对于标记为 ¹ 的优先级级别,没有具有该优先级级别的运算符子例程(通常是因为该优先级级别的运算符由编译器特殊处理)。这意味着在设置 自定义运算符的优先级 时,您无法访问该优先级级别。

  • 表示 项目赋值,而 表示 列表赋值运算符

运算符结合性§

当两个具有相同优先级级别的运算符作用于一个操作数时,运算符的结合性决定了哪个子表达式/运算符先被评估。例如,在表达式 100 / 2 * 10 中,二元除法运算符 / 和二元乘法运算符 * 具有相同的优先级,因此它们的评估顺序由它们的结合性决定。由于这两个运算符是左结合的,因此操作从左到右分组,如下所示:(100 / 2) * 10。因此,该表达式计算结果为 500。相反,如果 /* 都是右结合的,则该表达式将被分组为 100 / (2 * 10),并计算结果为 5

下表显示了每种结合性如何影响对涉及三个具有相同优先级和相同结合性的运算符的表达式的解释(使用虚构的中缀 § 运算符)

结合性$a § $b § $c § $d 的含义
(($a § $b) § $c) § $d
$a § ($b § ($c § $d))
非法
($a § $b) 和 ($b § $c) 和 ($c § $d)
列表infix:<§>($a, $b, $c, $d)

虽然此表仅描述中缀运算符,但结合性也决定了包含其他类型运算符的表达式的求值顺序。例如,如果您创建了一个优先级为 equiv(&prefix:<~>) 的中缀 § 运算符,那么 ~$a § $b 的求值顺序将取决于您为 § 指定的结合性。如果 § 是左结合的,那么 ~$a 将首先被求值,然后传递给 §;如果 § 是右结合的,那么 $a § $b 将首先被求值,然后传递给 ~

当两个运算符具有相同的优先级但不同的结合性时,确定操作数的组合会更加复杂。但是,对于 Raku 中内置的运算符,所有具有相同优先级级别的运算符也具有相同的结合性。

设置非中缀运算符的结合性尚未实现。

在下面的运算符描述中,假设默认结合性为

运算符分类§

运算符可以在相对于项的几个位置出现

+term前缀
term1 + term2中缀
term++后缀
(term)环缀
term1[term2]后环缀
.+(term)方法

每个运算符(方法运算符除外)也可以作为子例程使用。例程的名称由运算符类别、冒号以及包含构成运算符的符号的列表引用构成

infix:<+>(12);                # same as 1 + 2 
circumfix:«[ ]»(<a b c>);       # same as [<a b c>]

作为特殊情况,listop(列表运算符)可以作为项或前缀使用。子例程调用是最常见的 listop。其他情况包括元约简的中缀运算符([+] 1, 2, 3)以及 prefix ... 等存根运算符。

定义自定义运算符在 定义运算符函数 中介绍。

替换运算符§

每个替换运算符都有两种主要形式:小写形式(例如,s///)执行就地(即破坏性行为;以及大写形式(例如,S///)提供非破坏性行为。

s/// 就地替换§

my $str = 'old string';
$str ~~ s/.+ d/new/;
say $str# OUTPUT: «new string␤»

s///$_ 主题变量进行操作,就地更改它。它使用给定的 Regex 查找要替换的部分,并将它们更改为提供的替换字符串。将 $/ 设置为 Match 对象,或者如果进行了多次匹配,则设置为 ListMatch 对象。返回 $/

通常将此运算符与 ~~ 智能匹配运算符一起使用,因为它将左侧别名为 $_,而 s/// 使用 $_

正则表达式捕获可以在替换部分中引用;它采用与 .subst 方法 相同的副词,这些副词位于 s 和打开的 / 之间,用可选的空格隔开

my $str = 'foo muCKed into the lEn';
 
# replace second 'o' with 'x' 
$str ~~ s:2nd/o/x/;
 
# replace 'M' or 'L' followed by non-whitespace stuff with 'd' 
# and lower-cased version of that stuff: 
$str ~~ s :g :i/<[ML]> (\S+)/d{lc $0}/;
 
say $str# OUTPUT: «fox ducked into the den␤»

您也可以使用不同的分隔符

my $str = 'foober';
$str ~~ s!foo!fox!;
$str ~~ s{b(.)r} = " d$0n";
say $str# OUTPUT: «fox den␤»

非配对字符可以简单地替换原始斜杠。配对字符,如花括号,仅用于匹配部分,替换部分由赋值(任何内容:字符串、例程调用等)给出。

S/// 非破坏性替换§

say S/.+ d/new/ with 'old string';      # OUTPUT: «new string␤» 
S:g/« (.)/$0.uc()/.say for <foo bar ber># OUTPUT: «Foo␤Bar␤Ber␤»

S/// 使用与 s/// 运算符相同的语义,只是它保留原始字符串并返回结果字符串,而不是 $/$/ 仍然设置为与 s/// 相同的值)。

注意:由于结果是作为返回值获得的,因此将此运算符与 ~~ 智能匹配运算符一起使用是一个错误,并将发出警告。要对不是 $_ 的变量执行替换,请使用 givenwith 或任何其他方式将其别名为 $_。或者,使用 .subst 方法

tr/// 原地音译§

my $str = 'old string';
$str ~~ tr/dol/wne/;
say $str# OUTPUT: «new string␤»

tr/// 操作$_ 主题变量并原地修改它。它的行为类似于使用单个 Pair 参数调用的 Str.trans,其中键是匹配部分(上面示例中的字符 dol),值是替换部分(上面示例中的字符 wne)。接受与 Str.trans 相同的副词。返回 StrDistance 对象,该对象测量原始值和结果字符串之间的距离。

my $str = 'old string';
$str ~~ tr:c:d/dol st//;
say $str# OUTPUT: «old st␤»

TR/// 非破坏性音译§

with 'old string' {
    say TR/dol/wne/# OUTPUT: «new string␤» 
}

TR/// 的行为与 tr/// 运算符相同,只是它不会修改 $_ 值,而是返回结果字符串。

say TR:d/dol // with 'old string'# OUTPUT: «string␤»

赋值运算符§

Raku 有各种赋值运算符,可以大致分为简单赋值运算符和复合赋值运算符。

简单赋值运算符符号是 =。它在某种意义上是“重载的”,因为它可以表示 项目赋值列表赋值,具体取决于它使用的上下文。

my $x = 1;        # item assignment; $x = 1 
my @x = 1,2,3;    # list assignment; @x = [1,2,3]

有关这两种赋值类型的更详细和比较讨论,请参阅 项目和列表赋值 部分。

复合赋值运算符是 元运算符:它们将简单赋值运算符 = 与一个中缀运算符组合起来,形成一个新的运算符,该运算符在将结果赋值给左操作数之前执行中缀运算符指定的运算。一些内置复合赋值运算符的示例包括 +=-=*=/=min=~=。以下是它们的工作原理。

my $a = 32;
$a += 10;         # $a = 42 
$a -= 2;          # $a = 40 
 
$a = 3;
$a min= 5;        # $a = 3 
$a min= 2;        # $a = 2 
 
my $s = 'a';
$s ~= 'b';        # $s = 'ab' 
 
# And an example of a custom operator: 
sub infix:<space-concat> ($a$b{ $a ~ " " ~ $b };
my $a = 'word1';
$a space-concat= 'word2';                 # OUTPUT: «'word1 word2'␤»

简单和复合赋值运算符的一个共同点是,它们形成所谓的赋值表达式,这些表达式返回或计算为赋值的值。

my sub fac (Int $n{ [*1..$n };        # sub for calculating factorial 
my @x = ( my $y = fac(100), $y*101 );     # @x = [100!, 101!] 
 
my $i = 0;
repeat { say $i } while ($i += 1< 10;   # OUTPUT: «0,1,2,...9␤»

在第一个示例中,赋值表达式 my $y = fac(100) 声明 $y,将值 fac(100) 赋值给它,最后返回赋值的值 fac(100)。然后将返回的值用于构造列表。在第二个示例中,复合赋值表达式 $i += 1 将值 $i + 1 赋值给 $i,然后计算为赋值的值 $i+1,从而允许使用返回的值来判断 while 循环条件。

在处理简单和复合赋值运算符时,很容易认为以下两个语句(总是)等效。

expression1 += expression2;                     # compound assignment
expression1  = expression1 + expression2;       # simple assignment

然而,它们并非如此,原因有两个。首先,复合赋值语句中的 expression1 只计算一次,而简单赋值语句中的 expression1 计算两次。其次,复合赋值语句可能会根据所用中缀运算符,隐式地初始化 expression1(如果它是一个具有未定义值的变量)。简单赋值语句中的 expression1 不会发生这种初始化。

下面简要说明了上述简单和复合赋值语句之间的两个区别。

第一个区别在编程语言中很常见,而且大多不言自明。在复合赋值中,只有一个 expression1 被明确指定,它既用作要执行的加法的项,也用作存储加法结果(即总和)的位置。因此,无需计算它两次。相比之下,简单赋值更通用,因为用作加法项的 expression1 的值不一定与定义总和必须存储的位置的 expression1 的值相同。因此,这两个表达式是分别计算的。这种区别在 expression1 的计算对一个或多个变量产生副作用的情况下尤其重要。

my @arr = [102030];
my $i = 0;
 
if rand < 1/2 {
    @arr[++$i+= 1;                # @arr = [10,21,30] 
} else {
    @arr[++$i= @arr[++$i+ 1;    # @arr = [10,31,30] (or [10,20,21]?) 
}                                   # the result may be implementation-specific 
say @arr;

上面指出的第二个区别与在累加器模式中广泛使用复合赋值运算符有关。这种模式涉及一个所谓的累加器:一个变量,它在循环中计算一系列值的总和或乘积。为了避免需要显式累加器初始化,Raku 的复合赋值运算符在合理的情况下会静默地处理初始化。

my @str = "Cleanliness is next to godliness".comb;
my ($len$str);
for @str -> $c {
  $len += 1;
  $str ~= $c;
}
say "The string '$str' has $len characters.";

在这个例子中,累加器 $len$str 被隐式初始化为 0"",分别说明初始化值是特定于运算符的。在这方面,还注意到并非所有复合赋值运算符都能合理地初始化未定义的左侧变量。例如,/= 运算符不会任意选择被除数的值;相反,它会抛出异常。

虽然不严格是运算符,但方法可以像复合赋值运算符一样使用。

my $a = 3.14;
$a .= round;      # $a = $a.round; OUTPUT: «3»

元运算符§

元运算符可以像函数可以接受其他函数作为参数一样,用其他运算符或子例程参数化。要使用子例程作为参数,请在其名称前加上 &。Raku 会在后台生成实际的组合运算符,允许将该机制应用于用户定义的运算符。为了消除链式元运算符的歧义,将内部运算符括在方括号中。接下来将解释许多具有不同语义的元运算符。

否定关系运算符§

返回 Bool 的关系运算符的结果可以通过在前面加上 ! 来否定。为了避免与 !! 运算符产生视觉上的混淆,您不能修改任何以 ! 开头的运算符。

!==!eq 有快捷方式,即 !=ne

my $a = True;
say so $a != True;    # OUTPUT: «False␤» 
my $i = 10;
 
my $release = Date.new(:2015year, :12month, :24day);
my $today = Date.today;
say so $release !before $today;     # OUTPUT: «False␤»

反转运算符§

任何中缀运算符都可以通过在前面加上 R 来反转其两个参数。操作数的结合性也会反转。

say 4 R/ 12;               # OUTPUT: «3␤» 
say [R/2416;         # OUTPUT: «2␤» 
say [RZ~] <1 2 3>,<4 5 6>  # OUTPUT: «(41 52 63)␤»

超运算符§

超运算符包括 «»,以及它们的 ASCII 变体 <<>>。它们将一个给定的运算符(在单目运算符的情况下,用 « 和/或 » 包围或在其前面或后面)应用于一个或两个列表,返回结果列表,其中 «» 的尖端指向较短的列表。单个元素将转换为列表,因此它们也可以使用。如果其中一个列表比另一个列表短,则运算符将循环遍历较短的列表,直到处理完较长列表的所有元素。

say (123) »*» 2;          # OUTPUT: «(2 4 6)␤» 
say (1234) »~» <a b>;   # OUTPUT: «(1a 2b 3a 4b)␤» 
say (123) »+« (456);  # OUTPUT: «(5 7 9)␤» 
say (&sin&cos&sqrt.(0.5);
# OUTPUT: «(0.479425538604203 0.877582561890373 0.707106781186548)␤»

最后一个例子说明了如何将后缀运算符(在本例中为 .())也进行超运算。

my @a = <1 2 3>;
my @b = <4 5 6>;
say (@a,@b)»[1]; # OUTPUT: «(2 5)␤»

在本例中,是 后缀[] 被超运算。

赋值元运算符可以被超运算

my @a = 123;
say @a »+=» 1;    # OUTPUT: «[2 3 4]␤» 
my ($a$b$c);
(($a$b), $c) «=» ((12), 3);
say "$a$c";       #  OUTPUT: «1, 3␤»

单目运算符的超形式将尖端指向运算符,将钝端指向要操作的列表。

my @wisdom = TrueFalseTrue;
say !« @wisdom;     # OUTPUT: «[False True False]␤» 
 
my @a = 123;
@a»++;
say @a;             # OUTPUT: «[2 3 4]␤»

超运算符在嵌套数组上递归定义。

say -« [[12], 3]; # OUTPUT: «[[-1 -2] -3]␤»

此外,方法可以以无序、并发的方式调用。结果列表将按顺序排列。请注意,所有超运算符都是并行化的候选者,如果方法有副作用,会导致错误。优化器对超运算符有完全的控制权,这就是为什么它们不能由用户定义的原因。

class CarefulClass { method take-care {} }
my CarefulClass @objs;
my @results = @objs».take-care();
 
my @slops;        # May Contain Nuts 
@slops».?this-method-may-not-exist();

超运算符可以与哈希一起使用。尖端方向指示在结果哈希中是否忽略缺少的键。封闭的运算符对两个哈希中都有键的所有值进行操作。

%foo «+» %bar;键的交集
%foo »+« %bar;键的并集
%outer »+» %inner;只有 %inner 中存在于 %outer 中的键才会出现在结果中
my %outer = 123 Z=> <a b c>;
my %inner = 12 Z=> <x z>;
say %outer «~» %inner;          # OUTPUT: «{"1" => "ax", "2" => "bz"}␤»

超运算符可以接受用户定义的运算符作为其运算符参数。

sub pretty-file-size (Int $size --> Str{
    # rounding version of infix:</>(Int, Int) 
    sub infix:<r/>(Int \i1Int \i2{
        round(i1 / i20.1)
    }
 
    # we build a vector of fractions of $size and zip that with the fitting prefix 
    for $size «[r/]« (2**602**502**402**302**202**10)
              Z      <EB     PB     TB     GB     MB     KB> -> [\v,\suffix{
        # starting with the biggest suffix, 
        # we take the first that is 0.5 of that suffix or bigger 
        return v ~ ' ' ~ suffix if v > 0.4
    }
    # this be smaller or equal then 0.4 KB 
    return $size.Str;
}
 
for 605040302010 -> $test {
    my &a = { (2 ** $test* (1/41/2110100).pick * (1..10).pick };
    print pretty-file-size(a.Intxx 2' ';
}
 
# OUTPUT: «10 EB 4 EB 2 PB 5 PB 0.5 PB 4 TB 300 GB 4.5 GB 50 MB 200 MB 9 KB 0.6 MB␤»

超运算符是否下降到子列表取决于链的内部运算符的 节点性。对于超方法调用运算符 (».),目标方法的节点性很重要。

say (<a b>, <c d e>.elems;        # OUTPUT: «(2 3)␤» 
say (<a b>, <c d e>.&{ .elems };  # OUTPUT: «((1 1) (1 1 1))␤»

您可以将超运算符链接起来以解构列表的列表。

my $neighbors = ((-10), (0-1), (01), (10));
my $p = (23);
say $neighbors »>>+<<» ($p*);   # OUTPUT: «((1 3) (2 2) (2 4) (3 3))␤»

归约元运算符§

归约元运算符 [ ] 使用给定的中缀运算符归约列表。它给出的结果与 reduce 例程相同 - 有关详细信息,请参见那里。

# These two are equivalent: 
say [+123;                # OUTPUT: «6␤» 
say reduce &infix:<+>123# OUTPUT: «6␤»

方括号和运算符之间不允许有空格。要包装函数而不是运算符,请提供额外的方括号层。

sub plus { $^a + $^b };
say [[&plus]] 123;          # OUTPUT: «6␤»

参数列表在不展平的情况下进行迭代。这意味着您可以将嵌套列表传递给列表中缀运算符的归约形式。

say [X~] (12), <a b>;         # OUTPUT: «(1a 1b 2a 2b)␤»

它等效于 1, 2 X~ <a b>

默认情况下,只返回归约的最终结果。在包装的运算符前加上 \,以返回所有中间值的延迟列表。这称为“三角形归约”。如果非元部分已经包含 \,请用 [] 引用它(例如 [\[\x]])。

my @n = [\~1..*;
say @n[^5];         # OUTPUT: «(1 12 123 1234 12345)␤»

交叉元运算符§

交叉元运算符 X 将按交叉积的顺序将给定的中缀运算符应用于所有列表,使得最右边的操作数变化最快。

1..3 X~ <a b> # OUTPUT: «<1a, 1b, 2a, 2b, 3a, 3b>␤»

Zip 元运算符§

Zip 元运算符(与 Z 不同)将给定的中缀运算符应用于从其参数中取出的左、右对。返回结果列表。

my @l = <a b c> Z~ 123;     # OUTPUT: «[a1 b2 c3]␤»

如果其中一个操作数过早地用完元素,则 zip 运算符将停止。可以使用无限列表来重复元素。具有 * 作为最后一个元素的列表将无限期地重复其倒数第二个元素。

my @l = <a b c d> Z~ ':' xx *;  # OUTPUT: «<a: b: c: d:>» 
   @l = <a b c d> Z~ 12*;   # OUTPUT: «<a1 b2 c2 d2>»

如果没有给出中缀运算符,则默认情况下将使用 ,(逗号运算符)。

my @l = 1 Z 2;  # OUTPUT: «[(1 2)]»

顺序运算符§

顺序元运算符 S 将抑制优化器执行的任何并发或重新排序。大多数简单中缀运算符都支持。

say so 1 S& 2 S& 3;  # OUTPUT: «True␤»

元运算符的嵌套§

为了避免在链接元运算符时出现歧义,请使用方括号来帮助编译器理解您。

my @a = 123;
my @b = 567;
@a X[+=@b;
say @a;         # OUTPUT: «[19 20 21]␤»

术语优先级§

术语 < >§

quote-words 结构在空格处分解内容并返回一个 List 的单词。如果一个单词看起来像数字字面量或 Pair 字面量,它将被转换为相应的数字。

say <a b c>[1];   # OUTPUT: «b␤»

术语 ( )§

分组运算符.

空组 () 创建一个 空列表。非空表达式周围的括号只是对表达式进行结构化,但没有额外的语义。

在参数列表中,在参数周围加上括号可以防止它被解释为命名参数。

multi p(:$a!{ say 'named'      }
multi p($a)   { say 'positional' }
p => 1;           # OUTPUT: «named␤» 
p (=> 1);         # OUTPUT: «positional␤»

术语 { }§

BlockHash 构造函数。

如果内容为空,或者包含一个以 Pair 字面量或 %-sigiled 变量开头的单个列表,并且没有使用 $_ 变量 或占位符参数,则构造函数返回一个 Hash。否则,它将构造一个 Block

要强制构造 Block,请在左大括号后加上分号。要始终确保您最终得到一个 Hash,您可以使用 %( ) 转换器或 hash 例程。

{}.^name.say;        # OUTPUT: «Hash␤» 
{;}.^name.say;       # OUTPUT: «Block␤» 
 
{:$_}.^name.say;     # OUTPUT: «Block␤» 
%(:$_).^name.say;    # OUTPUT: «Hash␤» 
hash(:$_).^name.say# OUTPUT: «Hash␤»

环绕 [ ]§

数组构造函数 返回一个项目化的 Array,它在列表上下文中不会展平。检查一下

say .raku for [3,2,[1,0]]; # OUTPUT: «3␤2␤$[1, 0]␤»

此数组是逐项列出的,因为每个元素都构成一个项目,如数组最后一个元素前的 $ 所示,即 (列表) 项目上下文化器

术语§

术语有其 自己的扩展文档

方法后缀优先级§

后缀环绕 [ ]§

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

对 @容器中零个或多个元素进行位置访问的通用接口,也称为 "数组索引运算符"。

my @alphabet = 'a' .. 'z';
say @alphabet[0];                   # OUTPUT: «a␤» 
say @alphabet[1];                   # OUTPUT: «b␤» 
say @alphabet[*-1];                 # OUTPUT: «z␤» 
say @alphabet[100]:exists;          # OUTPUT: «False␤» 
say @alphabet[1701020].join;  # OUTPUT: «raku␤» 
say @alphabet[23 .. *].raku;        # OUTPUT: «("x", "y", "z")␤» 
 
@alphabet[12= "B""C";
say @alphabet[0..3].raku;           # OUTPUT: «("a", "B", "C", "d")␤»

有关此运算符行为的更详细说明以及如何在自定义类型中实现对它的支持,请参阅 下标

后缀环绕 { }§

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

对 %容器中零个或多个元素进行关联访问的通用接口,也称为 "哈希索引运算符"。

my %color = kiwi => "green"banana => "yellow"cherry => "red";
say %color{"banana"};                 # OUTPUT: «yellow␤» 
say %color{"cherry""kiwi"}.raku;    # OUTPUT: «("red", "green")␤» 
say %color{"strawberry"}:exists;      # OUTPUT: «False␤» 
 
%color{"banana""lime"} = "yellowish""green";
%color{"cherry"}:delete# note that value is always returned but removal only happens when delete is true. 
say %color;             # OUTPUT: «banana => yellowish, kiwi => green, lime => green␤»

有关便捷快捷方式,请参阅 后缀环绕 < >后缀环绕 « »,有关此运算符行为的更详细说明以及如何在自定义类型中实现对它的支持,请参阅 下标

后缀环绕 <>§

解容器化运算符,它从容器中提取值并使其独立于容器类型。

use JSON::Tiny;
 
my $config = from-json('{ "files": 3, "path": "/home/some-user/raku.rakudoc" }');
say $config.raku;      # OUTPUT: «${:files(3), :path("/home/some-user/raku.rakudoc")}␤» 
my %config-hash = $config<>;
say %config-hash.raku# OUTPUT: «{:files(3), :path("/home/some-user/raku.rakudoc")}␤» 

在两种情况下它都是一个 哈希,并且可以像那样使用;但是,在第一种情况下它处于项目上下文中,而在第二种情况下它已被提取到其适当的上下文中。

后缀环绕 < >§

后缀环绕 { } 的快捷方式,它使用与同名 引用词运算符 相同的规则引用其参数。

my %color = kiwi => "green"banana => "yellow"cherry => "red";
say %color<banana>;               # OUTPUT: «yellow␤» 
say %color<cherry kiwi>.raku;     # OUTPUT: «("red", "green")␤» 
say %color<strawberry>:exists;    # OUTPUT: «False␤»

从技术上讲,这不是真正的运算符;它是在编译时转换为 { } 后缀环绕运算符的语法糖。

后缀环绕 « »§

后缀环绕 { } 的快捷方式,它使用与同名 插值引用词运算符 相同的规则引用其参数。

my %color = kiwi => "green"banana => "yellow"cherry => "red";
my $fruit = "kiwi";
say %color«cherry "$fruit"».raku;   # OUTPUT: «("red", "green")␤»

从技术上讲,这不是真正的运算符;它是在编译时转换为 { } 后缀环绕运算符的语法糖。

后缀环绕 ( )§

调用运算符 将调用者视为 可调用 并调用它,使用括号之间的表达式作为参数。

请注意,标识符后跟一对括号始终被解析为子例程调用。

如果您希望您的对象响应调用运算符,请实现 方法 CALL-ME

方法运算符 .§

用于调用一个方法的运算符,$invocant.method

从技术上讲,这不是真正的运算符;它是在编译器中特殊处理的语法。

方法运算符 .&§

用于调用 可调用 的运算符,例如 方法 或使用方法语法的 子例程。调用者将绑定到第一个位置参数(因此如果 可调用 不接受至少一个位置参数,则调度将失败)。

从技术上讲,这不是真正的运算符;它是在编译器中特殊处理的语法。

my sub f($invocant){ "The arg has a value of $invocant" }
42.&f;
# OUTPUT: «The arg has a value of 42␤» 
 
42.&(-> $invocant { "The arg has a value of $invocant" });
# OUTPUT: «The arg has a value of 42␤»

方法运算符 .=§

变异方法调用$invocant.=method 会反糖化为 $invocant = $invocant.method,类似于 = (项目赋值)

从技术上讲,这不是真正的运算符;它是在编译器中特殊处理的语法。

方法运算符 .^§

一个 元方法调用$invocant.^method$invocant 的元类上调用 method。它会被糖化为 $invocant.HOW.method($invocant, ...)。有关更多信息,请参阅 元对象协议文档

从技术上讲,它不是真正的运算符;它是在编译器中特殊处理的语法。它也可以在类中应用,用于访问 self 上的元方法。

class Foo {
    has $.a = 3;
    method bar {
        return $.^name
    }
};
say Foo.new.bar# OUTPUT: «Foo␤» 

方法运算符 .?§

安全调用运算符$invocant.?method 如果 $invocant 有名为 method 的方法,则调用该方法。否则,它将返回 Nil

从技术上讲,这不是真正的运算符;它是在编译器中特殊处理的语法。

方法运算符 .+§

$foo.+meth 遍历 MRO 并调用所有名为 meth 的方法以及如果类型与 $foo 的类型相同,则调用名为 meth 的子方法。这些方法可能是多方法,在这种情况下,将调用匹配的候选方法。

之后,将返回一个包含结果的 List。如果未找到此类方法,则会抛出 X::Method::NotFound 异常。

class A {
  method foo { say "from A"}
}
class B is A {
  multi method foo { say "from B"}
  multi method foo(Str{ say "from B (Str)"}
}
class C is B is A {
  multi method foo { say "from C"}
  multi method foo(Str{ say "from C (Str)"}
}
 
say C.+foo# OUTPUT: «from C␤from B␤from A␤(True True True)␤»

方法运算符 .*§

$foo.*meth 遍历 MRO 并调用所有名为 meth 的方法以及如果类型与 $foo 的类型相同,则调用名为 meth 的子方法。这些方法可能是多方法,在这种情况下,将调用匹配的候选方法。

之后,将返回一个包含结果的 List。如果未找到此类方法,则将返回一个空的 List

从技术上讲,后缀 .+ 首先调用 .*。阅读后缀 .+ 部分以查看示例。

方法运算符 ». / 方法运算符 >>.§

这是 超方法调用运算符。它将在 List 的所有元素上无序地调用方法,并按顺序返回返回值列表。

my @a = <a b c>;
my @b = @a».ord;                  # OUTPUT: «[97, 98, 99]␤» 
# The first parameter of a method is the invocant. 
sub foo(Str:D $c){ $c.ord * 2 };
# So we can pretend to have a method call with a sub that got a good 
# first positional argument. 
say @a».&foo;
# Blocks have an implicit positional arguments that lands in $_. The latter can 
# be omitted for method calls. 
say @a».&{ .ord};

超方法调用可能看起来与执行 map 调用相同,但是除了作为对编译器的提示,它可以并行化调用之外,其行为还受 方法的节点性 的影响,具体取决于使用 nodemapdeepmap 语义来执行调用。

通过查找 Callable 是否提供 nodal 方法来检查节点性。如果超方法应用于方法,则该 Callable 是该方法名称,在 List 类型上查找;如果超方法应用于例程(例如 ».&foo),则该例程充当该 Callable。如果确定 Callable 提供 nodal 方法,则使用 nodemap 语义执行超方法调用,否则使用 duckmap 语义。

注意避免 常见错误,即期望副作用按顺序发生。以下 say **不** 保证按顺序生成输出

@a».say;  # WRONG! Could produce a␤b␤c␤ or c␤b␤a␤ or any other order 

方法运算符 .postfix / .postcircumfix§

在大多数情况下,可以在后缀或后缀环绕符之前放置一个点。

my @a;
@a[123];
@a.[123]; # Same

这对于视觉清晰度或简洁性很有用。例如,如果对象的属性是函数,则在属性名称后放置一对括号将成为方法调用的一部分。因此,必须使用两对括号,或者必须在括号之前放置一个点以将其与方法调用分开。

class Operation {
    has $.symbol;
    has &.function;
}
my $addition = Operation.new(:symbol<+>:function{ $^a + $^b });
say $addition.function()(12);   # OUTPUT: «3␤» 
# OR 
say $addition.function.(12);    # OUTPUT: «3␤»

但是,如果后缀是标识符,则它将被解释为普通方法调用。

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

从技术上讲,这不是真正的运算符;它是在编译器中特殊处理的语法。

方法运算符 .:<prefix operator>§

前缀形式的操作符仍然可以像方法一样调用,即使用.方法操作符符号,在它前面加上一个冒号。例如

my $a = 1;
say ++$a;       # OUTPUT: «2␤» 
say $a.:<++>;   # OUTPUT: «3␤»

从技术上讲,它不是真正的操作符;它是编译器中语法特殊情况,这就是为什么它被归类为方法操作符

方法操作符 .::§

一个类限定方法调用,用于调用父类或角色中定义的方法,即使它在子类中被重新定义。

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

后缀 ,=§

创建一个对象,以类相关的方式连接左侧变量的内容和右侧表达式的内容。

my %a = :11a, :22b;
%a ,= :33x;
say %a # OUTPUT: «{a => 11, b => 22, x => 33}␤»

自增优先级§

++§

multi prefix:<++>($x is rwis assoc<non>

将它的参数增加一并返回更新后的值。

my $x = 3;
say ++$x;   # OUTPUT: «4␤» 
say $x;     # OUTPUT: «4␤»

它通过调用它的参数的succ方法(表示后继)来工作,这使得自定义类型可以自由地实现自己的增量语义。

--§

multi prefix:<-->($x is rwis assoc<non>

将它的参数减少一并返回更新后的值。

my $x = 3;
say --$x;   # OUTPUT: «2␤» 
say $x;     # OUTPUT: «2␤»

它通过调用它的参数的pred方法(表示前驱)来工作,这使得自定义类型可以自由地实现自己的减量语义。

++§

multi postfix:<++>($x is rwis assoc<non>

将它的参数增加一并返回原始值。

my $x = 3;
say $x++;   # OUTPUT: «3␤» 
say $x;     # OUTPUT: «4␤»

它通过调用它的参数的succ方法(表示后继)来工作,这使得自定义类型可以自由地实现自己的增量语义;当未定义时,它将值设置为 1 并返回它。

my $x;
$x++;
say $x;     # OUTPUT: «1␤»

请注意,它并不一定返回它的参数;例如,对于未定义的值,它返回 0。

my $x;
say $x++;   # OUTPUT: «0␤» 
say $x;     # OUTPUT: «1␤»

Str的自增将增加字符串的数字部分并将结果字符串分配给容器。需要一个is rw容器。

my $filename = "somefile-001.txt";
say $filename++ for 1..3;
# OUTPUT: «somefile-001.txt␤somefile-002.txt␤somefile-003.txt␤»

这将作用于任何 Unicode 数字。

my $was٧ = "ثمانية٧";
$was٧++;
say $was٧# OUTPUT: «ثمانية٨␤» 

包括,从 6.d 版本开始,泰语数字。

my $เลขไทย="๙๙";
$เลขไทย++;
say $เลขไทย# OUTPUT: «๑๐๐␤» 

--§

multi postfix:<-->($x is rwis assoc<non>

将它的参数减少一并返回原始值。

my $x = 3;
say $x--;   # OUTPUT: «3␤» 
say $x;     # OUTPUT: «2␤»

它通过调用它的参数的pred方法(表示前驱)来工作,这使得自定义类型可以自由地实现自己的减量语义。

请注意,它并不一定返回它的参数;例如,对于未定义的值,它返回 0。

my $x;
say $x--;   # OUTPUT: «0␤» 
say $x;     # OUTPUT: «-1␤»

Str的自减将减少字符串的数字部分并将结果字符串分配给容器。需要一个is rw容器。越过 0 是禁止的,会抛出X::AdHoc

my $filename = "somefile-003.txt";
say $filename-- for 1..3;
# OUTPUT: «somefile-003.txt␤somefile-002.txt␤somefile-001.txt␤»

指数优先级§

中缀 **§

multi infix:<**>(AnyAny --> Numeric:Dis assoc<right>

指数操作符将两个参数都强制转换为Numeric,并计算左侧的值的右侧的值次方。

如果右侧是一个非负整数,而左侧是一个任意精度类型(IntFatRat),那么计算将不损失精度进行。

Unicode 上标将以完全相同的方式工作。

sub squaredInt $num ) { $num² };
say squared($_for ^5# OUTPUT: «0␤1␤4␤9␤16␤»

它也适用于多个 Unicode 上标数字的序列。

sub twenty-second-powerInt $num ) { $num²² };
say twenty-second-power($_for ^5# OUTPUT: «0␤1␤4194304␤31381059609␤17592186044416␤»

符号一元优先级§

前缀 ?§

multi prefix:<?>(Mu --> Bool:D)

布尔上下文运算符.

通过调用它的Bool方法,将参数强制转换为Bool。请注意,这会折叠Junction

前缀 !§

multi prefix:<!>(Mu --> Bool:D)

否定布尔上下文运算符.

通过调用它的Bool方法,将参数强制转换为Bool,并返回结果的否定。请注意,这会折叠Junction

前缀 //§

multi prefix:<//>(Any --> Bool:D)

布尔上下文运算符.

从 6.e 语言版本开始可用(Rakudo 编译器 2022.12+ 中存在早期实现)。

通过调用其上的 defined 方法将参数强制转换为 Boolean

前缀 +§

multi prefix:<+>(Any --> Numeric:D)

数值上下文运算符.

通过调用其上的 Numeric 方法将参数强制转换为 Numeric

前缀 -§

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

负数值上下文运算符.

通过调用其上的 Numeric 方法将参数强制转换为 Numeric,然后对结果取反。

前缀 ~§

multi prefix:<~>(Any --> Str:D)

字符串上下文运算符.

通过调用其上的 Str 方法将参数强制转换为 Str

前缀 |§

CapturePairListMapHash 类型的对象展平成参数列表。

sub slurpee|args ){
    say args.raku
};
slurpee( <a b c d>{ => 3 }'e' => 'f' => 33 )
# OUTPUT: «\(("a", "b", "c", "d"), {:e(3)}, :e(:f(33)))␤»

有关此主题的更多信息,请参阅 签名字面量页面,特别是关于捕获的部分

在参数列表之外,它返回一个 Slip,这使得它展平成外部列表。在 参数列表 中,Positional 被转换为位置参数,而 Associative 被转换为命名参数。

前缀 +^§

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

整数按位取反运算符:使用数字所需字节数加一将数字转换为二进制;翻转所有位并返回结果,假设它是 二进制补码 表示。

say +^255# OUTPUT: «-256␤» 

在这种情况下,255 是 11111111,需要一个字节。我们使用此值加一所需的字节表示,将其转换为 0000 0000 1111 1111。按位取反将其转换为 1111 1111 0000 0000,这是 -256 的二进制补码表示,它将被返回。

say +^1;        # OUTPUT: «-2␤» 
say +^(-256);   # OUTPUT: «255␤» 

负数被假定为二进制补码表示,因此循环回到原始数字。

前缀 ~^§

将参数强制转换为非变量编码字符串缓冲区类型(例如 buf8buf16buf32),然后翻转该缓冲区中的每个位。

请注意,这尚未实现。

前缀 ?^§

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

布尔按位取反运算符:将参数强制转换为 Bool,然后进行位翻转,这与 prefix:<!> 相同。

前缀 ^§

multi prefix:<^>(Any --> Range:D)

upto 运算符。

将参数强制转换为 Numeric,并生成一个从 0 到(但不包括)参数的范围。

say ^5;         # OUTPUT: «0..^5␤» 
for ^5 { }      # 5 iterations

点式中缀优先级§

这些运算符与其方法后缀对应物类似,但需要周围的空格(前后)来区分它们。

中缀 .=§

在左侧容器中的值上调用右侧方法,用结果值替换左侧容器中的值。

在大多数情况下,这与后缀变异符的行为相同,但优先级较低

my $a = -5;
say ++$a.=abs;
# OUTPUT: «6␤» 
say ++$a .= abs;
# OUTPUT: «Cannot modify an immutable Int␤ 
#           in block <unit> at <tmp> line 1␤␤» 

中缀 .§

在左侧调用者上调用以下方法(其名称必须是字母)。

请注意,运算符的中缀形式的优先级略低于后缀 .meth

say -5.abs;      # like: -(5.abs) 
# OUTPUT: «-5␤» 
say -5 . abs;    # like: (-5) . abs 
# OUTPUT: «5␤» 
say -5 .abs;     # following whitespace is optional 
# OUTPUT: «5␤»

乘法优先级§

中缀 *§

multi infix:<*>(AnyAny --> Numeric:D)

乘法运算符.

将两个参数强制转换为 Numeric 并相乘。结果为较宽的类型。有关详细信息,请参阅 Numeric

中缀 /§

multi infix:</>(AnyAny --> Numeric:D)

除法运算符.

将两个参数强制转换为 Numeric 并将左侧数字除以右侧数字。 Int 值的除法返回 Rat,否则 Numeric 中描述的“较宽类型”规则适用。

请注意,还有 div 用于 Int 除法。

中缀 div§

multi infix:<div>(Int:DInt:D --> Int:D)

整数除法运算符。向下取整。

请注意,还有 / 用于 Numeric 除法。

中缀 %§

multi infix:<%>($x$y --> Numeric:D)

取模运算符。首先强制转换为 Numeric

通常,以下恒等式成立

my ($x$y= 1,2;
$x % $y == $x - floor($x / $y* $y

请注意,还有 mod 用于 Int 取模。

中缀 %%§

multi infix:<%%>($a$b --> Bool:D)

可除性运算符。如果 $a % $b == 0,则返回 True

中缀 mod§

multi infix:<mod>(Int:D $aInt:D $b --> Int:D)

整数取模运算符。返回整数取模运算的余数。

请注意,还有 % 用于 Numeric 取模。

中缀 +&§

multi infix:<+&>($a$b --> Int:D)

数字按位运算符。将两个参数强制转换为 Int 并执行按位运算,假设为二进制补码。

中缀 +<§

multi infix:«+<»($a$b --> Int:D)

整数左移位。

中缀 +>§

multi infix:«+>»($a$b --> Int:D)

整数右移位。

中缀 ~&§

将每个参数强制转换为非变量编码字符串缓冲区类型(例如 buf8buf16buf32),然后对两个缓冲区的相应整数执行数字按位与运算,用零填充较短的缓冲区。

中缀 ~<§

将左侧参数强制转换为非变量编码字符串缓冲区类型(例如 buf8buf16buf32),然后对缓冲区的位执行数字按位左移。

请注意,这尚未实现。

中缀 ~>§

将左侧参数强制转换为非变量编码字符串缓冲区类型(例如 buf8buf16buf32),然后对缓冲区的位执行数字按位右移。

请注意,这尚未实现。

中缀 ?&§

multi infix:<?&>(Mu $x = Bool::True)
multi infix:<?&>(Mu \aMu \b)

布尔逻辑与运算符。将参数强制转换为 Bool 并对其执行逻辑与运算:当且仅当两个参数都为 True 时,它将返回 True。对于单个参数,它表现为恒等式,返回强制转换后的值。

中缀 gcd§

multi infix:<gcd>($a$b --> Int:D)

将两个参数强制转换为 Int 并返回最大公约数。 如果其中一个参数为 0,则返回另一个参数(当两个参数都为 0 时,运算符返回 0)。

中缀 lcm§

multi infix:<lcm>($a$b --> Int:D)

将两个参数强制转换为 Int 并返回最小公倍数;即,能被两个参数整除的最小整数。

加法优先级§

中缀 +§

multi infix:<+>($a$b --> Numeric:D)

加法运算符: 将两个参数强制转换为 Numeric 并将它们相加。从 6.d 版本开始,它也适用于 DurationDateTimeReal 类型。

中缀 -§

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

减法运算符: 将两个参数强制转换为 Numeric 并从第一个参数中减去第二个参数。从 6.d 版本开始,它也适用于 DurationDateTimeReal 类型。

中缀 +|§

multi infix:<+|>($a$b --> Int:D)

整数按位或运算符: 将两个参数强制转换为 Int 并执行按位(包含或)运算。

中缀 +^§

multi infix:<+^>($a$b --> Int:D)

整数按位异或运算符: 将两个参数强制转换为 Int 并执行按位异或(互斥或)运算。

say (0b00001101 +^ 0b00001001).base(2); # OUTPUT: «100␤» 

中缀 ~|§

将每个参数强制转换为非变量编码字符串缓冲区类型(例如 buf8buf16buf32),然后对两个缓冲区的对应整数执行数值按位或运算,用零填充较短的缓冲区。

中缀 ~^§

将每个参数强制转换为非变量编码字符串缓冲区类型(例如 buf8buf16buf32),然后对两个缓冲区的对应整数执行数值按位异或运算,用零填充较短的缓冲区。

中缀 ?^§

multi infix:<?^>(Mu $x = Bool::False)
multi infix:<?^>(Mu \aMu \b)

布尔逻辑异或运算符. 将参数强制转换为 Bool 并对其执行逻辑异或运算:当且仅当只有一个参数为 True 时,它将返回 True。对于单个参数,它表现为恒等运算,返回强制转换后的值。

中缀 ?|§

multi infix:<?|>(Mu $x = Bool::False)
multi infix:<?|>(Mu \aMu \b)

布尔逻辑或运算符. 将参数强制转换为 Bool 并对其执行逻辑或(包含或)运算:当至少一个参数为 True 时,它将返回 True。对于单个参数,它表现为恒等运算,返回强制转换后的值。

复制优先级§

中缀 x§

sub infix:<x>($a$b --> Str:D)

字符串重复运算符.

如果需要,将字符串 $a 转换为 Str,将 $b 转换为 Int,然后将字符串 $a 重复 $b 次。如果 $b <= 0,则返回空字符串。如果 $b-InfNaN,则会抛出异常 X::Numeric::CannotConvert

say 'ab' x 3;           # OUTPUT: «ababab␤» 
say 42 x 3;             # OUTPUT: «424242␤» 
 
my $a = 'a'.IO;
my $b = 3.5;
say $a x $b;            # OUTPUT: «aaa␤»

中缀运算符 xx§

multi infix:<xx>()
multi infix:<xx>(Mu \x)
multi infix:<xx>(&xNum:D() $n)
multi infix:<xx>(&xWhatever)
multi infix:<xx>(&xBool:D $b)
multi infix:<xx>(&xInt:D $n)
multi infix:<xx>(Mu \xNum:D() $n)
multi infix:<xx>(Mu \xWhatever)
multi infix:<xx>(Mu \xBool:D $b)
multi infix:<xx>(Mu \xInt:D $n)

列表重复运算符

通常,它返回一个 $a 重复并计算 $b 次的序列($b 被强制转换为 Int)。如果 $b <= 0,则返回空列表。它将返回一个没有操作数的错误,并返回一个操作数本身。如果 $b-InfNaN,则会抛出异常 X::Numeric::CannotConvert

左侧在每次重复时都会被评估,所以

say [12xx 5;
# OUTPUT: «([1 2] [1 2] [1 2] [1 2] [1 2])␤»

返回五个不同的数组(但每次内容相同),而

rand xx 3

返回三个独立确定的伪随机数。

右侧可以是 *,在这种情况下,将返回一个延迟的无限列表。如果它是一个 Bool,如果它是 True,则返回一个包含单个元素的 Seq

连接§

与其他中缀运算符一样,这些运算符可以与元运算符(例如 赋值)结合使用。

中缀运算符 ~§

multi infix:<~>(Any,   Any)
multi infix:<~>(Str:DStr:D)
multi infix:<~>(Buf:DBuf:D)
multi infix:<~>(Blob:D $aBlob:D $b)
multi infix:<~>(Junction:D \aJunction:D \b)

这是 字符串连接运算符,它将两个参数都强制转换为 Str 并连接它们。如果两个参数都是 Buf,则返回一个组合的缓冲区。

say 'ab' ~ 'c';     # OUTPUT: «abc␤» 
my $bob = Blob.new([1,2,3]);
my $bao = Blob.new([3,4,5]);
say $bao ~ $bob;     # OUTPUT: «Blob:0x<03 04 05 01 02 03>␤» 

当运算符的超版本用于包含单个元素的数组或列表,或者仅仅是元素时,将调用此运算符的一元版本。

say [~Blob.new([3,4,5]);     # OUTPUT: «Blob:0x<03 04 05>␤» 
say [~1|2;                   # OUTPUT: «any(1, 2)␤» 

中缀运算符 o,中缀运算符 §

multi infix:<o>()
multi infix:<o>(&f)
multi infix:<o>(&f&g --> Block:D)

函数组合运算符 infix:<∘>infix:<o> 组合两个函数,以便用右侧函数的返回值调用左侧函数。如果左侧函数的 .count 大于 1,则右侧函数的返回值将被 滑入 左侧函数。

右侧的 .count.arity 以及左侧的 .of 都将被保留。

sub f($p){ say 'f'$p / 2 }
sub g($p){ say 'g'$p * 2 }
 
my &composed = &f  &g;
say composed 2# OUTPUT: «g␤f␤2␤» 
# equivalent to: 
say 2.&g.&f;
# or to: 
say f g 2;
say &composed.arity#  OUTPUT: «1␤» 
say &composed.count#  OUTPUT: «1␤» 
say &composed.of;    #  OUTPUT: «(Mu)␤» 
sub f($a$b$c{ [~$c$b$a }
sub g($str){ $str.comb }
my &composed = &f  &g;
say composed 'abc'# OUTPUT: «cba␤» 
# equivalent to: 
say f |g 'abc';

单参数候选函数将返回给定的参数本身。零参数候选函数返回一个身份例程,它只返回其参数。

my &composed = [&uc;
say composed 'foo'# OUTPUT: «FOO␤» 
 
my &composed = [];
say composed 'foo'# OUTPUT: «foo␤»

连接 AND(全部)优先级§

中缀运算符 &§

multi infix:<&>($a$b --> Junction:Dis assoc<list>

全部连接运算符.

从其参数创建 全部 Junction。有关更多详细信息,请参阅 Junction

中缀运算符 (&),中缀运算符 §

multi infix:<(&)>(**@p)

交集运算符.

'&' 表示左侧参数 '和' 右侧参数。返回所有参数的 交集。如果所有参数都不是 BagBagHashMixMixHash,则这将创建一个新的 Set,其中只包含所有参数共有的元素。

say <a b c> (&) <b c d># OUTPUT: «Set(b c)␤» 
say <a b c d>  <b c d e>  <c d e f># OUTPUT: «Set(c d)␤» 

如果任何参数是 BaggyMixy,结果将是一个新的 Bag(或 Mix),其中包含公共元素,每个元素的权重都由最大的公共权重(即该元素在所有参数中的权重的最小值)加权。

say <a a b c a> (&) bag(<a a b c c>); # OUTPUT: «Bag(a(2) b c)␤» 

中缀 (.),中缀 §

multi infix:<(.)>(**@p)

宽松乘法运算符.

返回其参数的 Baggy 乘法,即一个 Bag,其中包含参数的每个元素,元素在参数中的权重相乘以获得新的权重。如果任何参数是 Mixy,则返回 Mix

say <a b c> (.) <a b c d># OUTPUT: «Bag(a b c)␤» 
                           # Since 1 * 0 == 0, in the case of 'd' 
say <a a b c a d>  bag(<a a b c c>); # OUTPUT: «Bag(a(6) b c(2))␤» 

合取 OR(任何)优先级§

中缀 |§

multi infix:<|>($a$b --> Junction:Dis assoc<list>

从其参数创建任何 Junction

my $three-letters = /<[a b c]>/ | /<[i j k]>/ | /<[x y z]>/;
say $three-letters.raku# OUTPUT: «any(/<[a b c]>/, /<[i j k]>/, /<[x y z]>/)␤» 
say 'b' ~~ $three-letters# OUTPUT: «True␤»

这首先创建一个包含三个正则表达式的 any Junction(每个正则表达式都匹配三个字母中的任何一个),然后使用智能匹配来检查字母 b 是否与其中任何一个匹配,从而导致匹配成功。有关更多详细信息,请参阅 Junction

中缀 (|),中缀 §

multi infix:<(|)>(**@p)

并集运算符.

'|' 表示左侧参数“或”右侧参数。

返回所有参数的并集。如果所有参数都不是 BagBagHashMixMixHash,则这将创建一个包含其参数包含的所有元素的新 Set

say <a b d>  bag(<a a b c>); # OUTPUT: «Bag(a(2) b c d)␤» 

如果任何参数是 BaggyMixy,结果将是一个新的 Bag(或 Mix),其中包含所有元素,每个元素的权重都由该元素出现的最高权重加权。

say <a b d>  bag(<a a b c>); # OUTPUT: «Bag(a(2) b c d)␤» 

中缀 (+),中缀 §

multi infix:<(+)>(**@p)

宽松加法运算符.

返回其参数的 Baggy 加法。如果所有参数都不是 MixMixHash,则这将从参数的每个元素创建一个新的 Bag,并将元素的权重加在一起以获得新的权重。

say <a a b c a d> (+) <a a b c c># OUTPUT: «Bag(a(5) b(2) c(3) d)␤» 

如果任何参数是 Mixy,结果将是一个新的 Mix

say <a b c> (+) (=> 2.5=> 3.14).Mix# OUTPUT: «Mix(a(3.5) b(4.14) c)␤» 

中缀 (-),中缀 §

multi infix:<(-)>(**@p)

集合差运算符.

返回所有参数的集合差。这将创建一个新的 Set,其中包含第一个参数具有的所有元素,但其余参数没有,即第一个参数的所有元素减去其他参数的元素。但这仅在所有参数都不是 BagBagHashMixMixHash 时才有效。

say <a a b c a d> (-) <a a b c c># OUTPUT: «Set(d)␤» 
say <a b c d e> (-) <a b c> (-) <a b d># OUTPUT: «Set(e)␤» 

如果任何参数是 BaggyMixy,结果将是一个新的 Bag(或 Mix),其中包含在第一个参数的权重减去该元素在其他每个参数中的权重后剩余的所有元素。

say <a a b c a d> (-) bag(<a b c c>); # OUTPUT: «Bag(a(2) d)␤» 
say <a a b c a d>    mix(<a b c c>); # OUTPUT: «Mix(a(2) c(-1) d)␤» 

中缀 ^§

multi infix:<^>($a$b --> Junction:Dis assoc<list>

单路连接运算符.

从其参数创建一个一个 Junction。有关更多详细信息,请参阅 Junction

中缀 (^),中缀 §

multi infix:<(^)>($a$b)
multi infix:<(^)>(**@p)

对称集合差运算符.

返回所有参数的对称集合差。这将创建一个新的 Set,它由 $a 具有而 $b 没有的所有元素以及 $b 具有而 $a 没有的所有元素组成,前提是所有参数都不是 BagBagHashMixMixHash。等效于 ($a ∖ $b) ∪ ($b ∖ $a)

say <a b> (^) <b c># OUTPUT: «Set(a c)␤» 

如果任何参数是 BaggyMixy,结果将是一个新的 Bag(或 Mix)。

say <a b>  bag(<b c>); # OUTPUT: «Bag(a c)␤» 

命名一元优先级§

前缀 temp§

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

“临时化”作为参数传递的变量。该变量以与外部作用域中相同的初始值开始,但可以在此作用域内被赋予新值。退出作用域后,该变量将恢复到其原始值。

my $a = "three";
say $a# OUTPUT: «three␤» 
{
    temp $a;
    say $a# OUTPUT: «three␤» 
    $a = "four";
    say $a# OUTPUT: «four␤» 
}
say $a# OUTPUT: «three␤»

您也可以在调用 temp 时立即赋值。

temp $a = "five";

请注意,一旦离开代码块,temp 的效果就会被移除。如果您要从例如一个 Promise 中访问该值,而 temp 已经被撤销,您将获得原始值,而不是 temp 值。

my $v = "original";
{
    temp $v = "new one";
    start {
        say "[PROMISE] Value before block is left: `$v`";
        sleep 1;
        say "[PROMISE] Block was left while we slept; value is now `$v`";
    }
    sleep ½;
    say "About to leave the block; value is `$v`";
}
say "Left the block; value is now `$v`";
sleep 2;
 
# OUTPUT: 
# [PROMISE] Value before block is left: `new one` 
# About to leave the block; value is `new one` 
# Left the block; value is now `original` 
# [PROMISE] Block was left while we slept; value is now `original` 

前缀 let§

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

引用外部作用域中的一个变量,如果代码块不成功退出,该变量的值将被恢复,这意味着代码块返回了一个已定义的对象。

my $name = "Jane Doe";
 
{
    let $name = prompt("Say your name ");
    die if !$name;
    CATCH {
        default { say "No name entered" }
    }
    say "We have $name";
}
 
say "We got $name";

此代码为 $name 提供了一个默认名称。如果用户退出提示或 simply does not provide a valid input for $namelet 将恢复在顶部提供的默认值。如果用户输入有效,它将保留该值。

非链式二元优先级§

中缀 does§

sub infix:<does>(Mu $objMu $roleis assoc<non>

在运行时将 $role 混合到 $obj 中。要求 $obj 是可变的。

类似于 but 运算符,如果 $role 恰好提供了一个属性,则可以在括号中传递一个初始化器。

类似于 but 运算符,$role 可以是一个实例化的对象,在这种情况下,运算符将自动为您创建一个角色。该角色将包含一个名为 $obj.^name 的方法,该方法返回 $obj

my $o = class { method Str { "original" } }.new;
put $o;            # OUTPUT: «original␤» 
$o does "modded";
put $o;            # OUTPUT: «modded␤»

如果存在相同名称的方法,则最后混合的角色优先。

中缀 but§

multi infix:<but>(Mu $obj1Mu   $roleis assoc<non>
multi infix:<but>(Mu $obj1Mu:D $obj2is assoc<non>

创建一个混合了 $role$obj 的副本。由于 $obj 没有被修改,因此 but 可以用来创建带有 mixins 的不可变值。

如果 $role 恰好提供了一个属性,则可以在括号中传递一个初始化器。

role Answerable {
    has $.answer;
}
my $ultimate-question = 'Life, the Universe and Everything' but Answerable(42);
say $ultimate-question;         # OUTPUT: «Life, the Universe and Everything␤» 
say $ultimate-question.^name;   # OUTPUT: «Str+{Answerable}␤» 
say $ultimate-question.answer;  # OUTPUT: «42␤» 

您可以提供一个实例化的对象,而不是角色。在这种情况下,运算符将自动为您创建一个角色。该角色将包含一个名为 $obj.^name 的方法,该方法返回 $obj

my $forty-two = 42 but 'forty two';
say $forty-two+33;    # OUTPUT: «75␤» 
say $forty-two.^name# OUTPUT: «Int+{<anon|1>}␤» 
say $forty-two.Str;   # OUTPUT: «forty two␤» 

调用 ^name 显示该变量是一个混合了匿名对象的 Int。但是,该对象是 Str 类型,因此该变量通过 mixin 被赋予了一个具有该名称的方法,这就是我们在最后一句话中使用的方法。

我们也可以混合类,甚至可以动态创建类。

my $s = 12 but class Warbles { method hi { 'hello' } }.new;
say $s.Warbles.hi;    # OUTPUT: «hello␤» 
say $s + 42;          # OUTPUT: «54␤» 

要访问混合的类,如上所示,我们使用类名,如第二句话所示。如果存在相同名称的方法,则最后混合的角色优先。可以在括号中提供一个用逗号分隔的方法列表。在这种情况下,冲突将在运行时报告。

中缀 cmp§

multi infix:<cmp>(Any,       Any)
multi infix:<cmp>(Real:D,    Real:D)
multi infix:<cmp>(Str:D,     Str:D)
multi infix:<cmp>(Version:DVersion:D)

通用的,“智能”三路比较器。.

使用字符串语义比较字符串,使用数字语义比较数字,Pair 对象首先按键比较,然后按值比较等。

如果 $a eqv $b,则 $a cmp $b 始终返回 Order::Same

say (=> 3cmp (=> 4);   # OUTPUT: «Less␤» 
say 4        cmp 4.0;        # OUTPUT: «Same␤» 
say 'b'      cmp 'a';        # OUTPUT: «More␤»

字符串按代码点进行比较;如果前导代码点相同,则返回比较第一个不同代码点的结果,或者如果它们的长度不同,则返回较长的字符串。

"abcd" cmp "abcde";    # OUTPUT: «Less␤» 
"abcd " cmp "abcde";   # OUTPUT: «Less␤» 
'A' cmp '';           # OUTPUT: «Less␤»

中缀 coll§

multi infix:<coll>(Str:D \aStr:D \b --> Order:D)
multi infix:<coll>(Cool:D \aCool:D \b --> Order:D)
multi infix:<coll>(Pair:D \aPair:D \b --> Order:D)

coll 是一个排序运算符,它接受一对 StrCoolPair,并返回一个使用 $*COLLATION 顺序的 Order。例如,默认行为会忽略变音符号和大小写。

say "b" cmp "à";  # OUTPUT: «Less␤» 
say "b" coll "à"# OUTPUT: «More␤»

在第一种情况下,会考虑词典顺序或代码点顺序。在第二种情况下,使用 coll,变音符号不会被考虑,排序会根据直观的顺序进行。

注意:这些在 JVM 中尚未实现。

中缀 unicmp§

multi infix:<unicmp>(Str:D \aStr:D \b --> Order:D)
multi infix:<unicmp>(Pair:D \aPair:D \b --> Order:D)
multi infix:<coll>(Pair:D \aPair:D \b --> Order:D)

与根据代码点排序的 cmp 运算符不同,unicmpcoll 根据大多数用户期望的方式进行排序,即忽略字符的特定方面,例如大小写。

say 'a' unicmp 'Z'# OUTPUT: «Less␤» 
say 'a' coll 'Z';   # OUTPUT: «Less␤» 
say 'a' cmp 'Z';    # OUTPUT: «More␤»

collunicmp 之间的主要区别在于,前者的行为可以通过 $*COLLATION 动态变量来改变。

注意:这些在 JVM 中尚未实现。

中缀 leg§

multi infix:<leg>(Any,   Any)
multi infix:<leg>(Str:DStr:D)

字符串三向比较器less, equal or greater? 的缩写。

将两个参数都强制转换为 Str,然后进行词典比较。

say 'a' leg 'b';       # OUTPUT: «Less␤» 
say 'a' leg 'a';       # OUTPUT: «Same␤» 
say 'b' leg 'a';       # OUTPUT: «More␤»

中缀 <=>§

multi infix:«<=>»($a$b --> Order:Dis assoc<non>

数值三向比较器

将两个参数都强制转换为 Real,然后进行数值比较。

中缀 ..§

multi infix:<..>($a$b --> Range:Dis assoc<non>

区间运算符

从参数构造一个 Range

中缀 ..^§

multi infix:<..^>($a$b --> Range:Dis assoc<non>

右开区间运算符.

从参数构造一个 Range,但不包括结束点。

中缀 ^..§

multi infix:<^..>($a$b --> Range:Dis assoc<non>

左开区间运算符.

从参数构造一个 Range,但不包括起点。

中缀 ^..^§

multi infix:<^..^>($a$b --> Range:Dis assoc<non>

开区间运算符.

从参数构造一个 Range,但不包括起点和结束点。

链式二元优先级§

中缀 ==,中缀 §

multi infix:<==>(AnyAny)
multi infix:<==>(Int:DInt:D)
multi infix:<==>(Num:DNum:D)
multi infix:<==>(Rational:DRational:D)
multi infix:<==>(Real:DReal:D)
multi infix:<==>(Complex:DComplex:D)
multi infix:<==>(Numeric:DNumeric:D)

数值相等运算符.

将两个参数都强制转换为 Numeric(如果需要);如果它们相等,则返回 True

从 Rakudo 版本 2021.07 开始,⩵ 是此运算符的别名。

中缀 !=,中缀 §

sub infix:<!=>(MuMu --> Bool:D)

数值不相等运算符.

将两个参数都强制转换为 Numeric(如果需要);如果它们不同,则返回 True

等效于 !==

中缀 <§

multi infix:«<»(Int:DInt:D)
multi infix:«<»(Num:DNum:D)
multi infix:«<»(Real:DReal:D)

数值小于运算符.

将两个参数都强制转换为 Real(如果需要);如果第一个参数小于第二个参数,则返回 True

中缀 <=,中缀 §

multi infix:«<=»(Int:DInt:D)
multi infix:«<=»(Num:DNum:D)
multi infix:«<=»(Real:DReal:D)

数值小于或等于运算符.

将两个参数都强制转换为 Real(如果需要);如果第一个参数小于或等于第二个参数,则返回 True

中缀 >§

multi infix:«>»(Int:DInt:D)
multi infix:«>»(Num:DNum:D)
multi infix:«>»(Real:DReal:D)

数值大于运算符.

将两个参数都强制转换为 Real(如果需要);如果第一个参数大于第二个参数,则返回 True

中缀 >=,中缀 §

multi infix:«>=»(Int:DInt:D)
multi infix:«>=»(Num:DNum:D)
multi infix:«>=»(Real:DReal:D)

数值大于或等于运算符.

将两个参数都强制转换为 Real(如果需要);如果第一个参数大于或等于第二个参数,则返回 True

中缀 eq§

multi infix:<eq>(Any,   Any)
multi infix:<eq>(Str:DStr:D)

字符串相等运算符.

将两个参数都强制转换为 Str(如果需要);如果两者相等,则返回 True

助记符:equal

中缀 ne§

multi infix:<ne>(Mu,    Mu)
multi infix:<ne>(Str:DStr:D)

字符串不相等运算符.

将两个参数强制转换为 Str(如果需要);如果两个参数相等,则返回 False

助记符:不相等

中缀 gt§

multi infix:<gt>(Mu,    Mu)
multi infix:<gt>(Str:DStr:D)

字符串大于运算符.

将两个参数强制转换为 Str(如果需要);如果第一个参数大于第二个参数,则返回 True,由词典顺序比较决定。

助记符:大于

中缀 ge§

multi infix:<ge>(Mu,    Mu)
multi infix:<ge>(Str:DStr:D)

字符串大于或等于运算符.

将两个参数强制转换为 Str(如果需要);如果第一个参数等于或大于第二个参数,则返回 True,由词典顺序比较决定。

助记符:大于或等于

中缀 lt§

multi infix:<lt>(Mu,    Mu)
multi infix:<lt>(Str:DStr:D)

字符串小于运算符.

将两个参数强制转换为 Str(如果需要);如果第一个参数小于第二个参数,则返回 True,由词典顺序比较决定。

助记符:小于

中缀 le§

multi infix:<le>(Mu,    Mu)
multi infix:<le>(Str:DStr:D)

字符串小于或等于运算符.

将两个参数强制转换为 Str(如果需要);如果第一个参数等于或小于第二个参数,则返回 True,由词典顺序比较决定。

助记符:小于或等于

中缀 before§

multi infix:<before>(Any,       Any)
multi infix:<before>(Real:D,    Real:D)
multi infix:<before>(Str:D,     Str:D)
multi infix:<before>(Version:DVersion:D)

通用排序,使用与 cmp 相同的语义。如果第一个参数小于第二个参数,则返回 True

中缀 after§

multi infix:<after>(Any,       Any)
multi infix:<after>(Real:D,    Real:D)
multi infix:<after>(Str:D,     Str:D)
multi infix:<after>(Version:DVersion:D)

通用排序,使用与 cmp 相同的语义。如果第一个参数大于第二个参数,则返回 True

中缀 eqv§

sub infix:<eqv>(AnyAny)

这可以被称为 等价运算符,如果两个参数在结构上相同,即来自相同的类型并且(递归地)包含等价的值,则它将返回 True

say [123eqv [123];    # OUTPUT: «True␤» 
say Any eqv Any;                # OUTPUT: «True␤» 
say 1 eqv 2;                    # OUTPUT: «False␤» 
say 1 eqv 1.0;                  # OUTPUT: «False␤»

延迟 Iterables 无法比较,因为它们被假定为无限的。但是,该运算符将尽力而为,如果两个延迟 Iterables 的类型不同,或者只有一个 Iterable 是延迟的,则返回 False

say (1…∞) eqv (1…∞).List# Both lazy, but different types;   OUTPUT: «False␤» 
say (1…∞) eqv (13);      # Same types, but only one is lazy; OUTPUT: «False␤» 
(try say (1…∞) eqv (1…∞)) # Both lazy and of the same type. Cannot compare; throws. 
    orelse say $!.^name;  # OUTPUT: «X::Cannot::Lazy␤»

在某些情况下,它将能够比较延迟操作数,只要它们可以迭代

my $a = lazy ^2;
my $b = $a;
$a.cache;
say $a eqv $b# OUTPUT: «True␤» 

当缓存时,两个延迟 Seqs 可以被迭代,因此可以比较。

默认的 eqv 运算符甚至适用于任意对象。例如,eqv 将认为同一个对象的两个实例在结构上是等价的

my class A {
    has $.a;
}
say A.new(=> 5eqv A.new(=> 5);  # OUTPUT: «True␤»

虽然上面的例子按预期工作,但 eqv 代码可能会回退到更慢的代码路径以完成其工作。避免这种情况的一种方法是实现一个合适的 infix eqv 运算符

my class A {
    has $.a;
}
multi infix:<eqv>(A $lA $r{ $l.a eqv $r.a }
say A.new(=> 5eqv A.new(=> 5);            # OUTPUT: «True␤»

请注意,eqv 不会对每种容器类型递归地工作,例如 Set

my class A {
    has $.a;
}
say Set(A.new(=> 5)) eqv Set(A.new(=> 5));  # OUTPUT: «False␤»

即使两个集合的内容是 eqv,集合也不是。原因是 eqv 将相等性检查委托给 Set 对象,该对象依赖于元素级的 === 比较。通过为类 A 提供一个 WHICH 方法,将其转换为值类型 (ValueObjAt) 会产生预期的行为

my class A {
    has $.a;
    method WHICH {
        ValueObjAt.new: "A|$!a.WHICH()"
    }
}
say Set(A.new(=> 5)) eqv Set(A.new(=> 5));  # OUTPUT: «True␤»

您可以通过使用运算符的完整名称来调用运算符的单参数版本;它将始终返回 true。

say infix:<eqv>(33);    # OUTPUT: «True␤» 
say infix:<eqv>(False); # OUTPUT: «True␤» 

中缀 ===,中缀 §

sub infix:<===>(AnyAny)

值标识运算符。如果两个参数是同一个对象,则返回 True,不考虑任何容器化。

my class A { };
my $a = A.new;
say $a === $a;              # OUTPUT: «True␤» 
say A.new === A.new;        # OUTPUT: «False␤» 
say A === A;                # OUTPUT: «True␤»

对于值类型,=== 的行为类似于 eqv

say 'a' === 'a';            # OUTPUT: «True␤» 
say 'a' === 'b';            # OUTPUT: «False␤» 
 
my $b = 'a';
say $b === 'a';             # OUTPUT: «True␤» 
 
# different types 
say 1 === 1.0;              # OUTPUT: «False␤»

=== 使用 WHICH 方法来获取对象标识。

如果您想创建一个应该充当值类型的类,那么该类必须创建一个实例方法 WHICH,该方法应该返回一个 ValueObjAt 对象,该对象在对象的整个生命周期内都不会改变。

从 Rakudo 版本 2021.07 开始,Unicode 字符 ⩶ 是此运算符的别名。

中缀 =:=§

multi infix:<=:=>(Mu \aMu \b)

容器标识运算符。如果两个参数都绑定到同一个容器,则返回 True。如果返回 True,通常意味着修改其中一个也会修改另一个。

my ($a$b= (13);
say $a =:= $b;      # OUTPUT: «False␤» 
$b = 2;
say $a;             # OUTPUT: «1␤» 
$b := $a;
say $a =:= $b;      # OUTPUT: «True␤» 
$a = 5;
say $b;             # OUTPUT: «5␤»

单参数版本,作为例程调用,将始终返回 True

say infix:<=:=>(42);    # OUTPUT: «True␤» 
say infix:<=:=>(False); # OUTPUT: «True␤» 

中缀 ~~§

智能匹配运算符将左侧别名为 $_,然后计算右侧并调用其上的 .ACCEPTS($_)。语义由右侧操作数的类型决定。

以下是部分内置智能匹配功能的列表。有关完整详细信息,请参阅右侧操作数类型上的 ACCEPTS 文档。

右侧比较语义
Mu:U类型检查
Str字符串相等
Numeric数值相等
Regex正则表达式匹配
Callable调用的布尔结果
Set/Bag元素值相等
Any:D对象标识

中缀 =~=,中缀 §

multi infix:<=~=>(AnyAny)
multi infix:<=~=>(Int:DInt:D)
multi infix:<=~=>(Num:DNum:D)
multi infix:<=~=>(Rational:DRational:D)
multi infix:<=~=>(Real:DReal:D)
multi infix:<=~=>(Complex:DComplex:D)
multi infix:<=~=>(Numeric:DNumeric:D)

近似相等运算符 ,其 ASCII 变体为 =~=,计算左侧和右侧的相对差,如果差小于 $*TOLERANCE(默认为 1e-15),则返回 True。但是,如果任一侧为零,则检查两侧之间的绝对差是否小于 $*TOLERANCE。请注意,此运算符在算术上不对称(不执行 ± Δ)

my $x = 1;
say ($x + $*TOLERANCE=~= $x;   # OUTPUT: «False␤» 
say ($x - $*TOLERANCE=~= $x;   # OUTPUT: «True␤»

您可以词法更改 $*TOLERANCE

{
    my $*TOLERANCE = .1;
    say 11 =~= 10;        # OUTPUT: «True␤» 
}

请注意,设置 $*TOLERANCE = 0 将导致所有比较失败。

{
    my $*TOLERANCE = 0;
    say 1 =~= 1;          # OUTPUT: «False␤» 
}

中缀 (elem),中缀 ∈§

multi infix:<(elem)>($a,$b --> Bool:D)

成员运算符.

如果 $a$b元素,则返回 True

say 2 (elem) (123); # OUTPUT: «True␤» 
say 4  (123);      # OUTPUT: «False␤» 

自 2020.05 版本起,∊ 是此运算符的别名。

中缀 §

multi infix:<>($a,$b --> Bool:D)

非成员运算符.

如果 $a 不是 $b元素,则返回 True。等效于 !(elem)

say 4  (123);       # OUTPUT: «True␤» 
say 2 !(elem) (123); # OUTPUT: «False␤» 

中缀 (==),中缀 ≡§

multi infix:<(==)>($a,$b --> Bool:D)

集合相等运算符.

如果 $a$b 相同,则返回 True

say (123) (==) (132); # OUTPUT: «True␤» 
say (123) ≡ (124); # OUTPUT: «False␤» 

中缀 §

multi infix:<>($a,$b --> Bool:D)

集合不相等运算符.

如果 $a$b 不同,则返回 True。等效于 !(==)

say (123) ≢ (124); # OUTPUT: «True␤» 
say (123) ≢ (132); # OUTPUT: «False␤» 

中缀 (cont),中缀 ∋§

multi infix:<(cont)>($a,$b --> Bool:D)

成员运算符.

如果 $a 包含 $b 作为元素,则返回 True

say (1,2,3(cont) 2# OUTPUT: «True␤» 
say (123 4;    # OUTPUT: «False␤» 

自 2020.05 版本起,∍ 是此运算符的别名。

中缀 §

multi infix:<>($a,$b --> Bool:D)

非成员运算符.

如果 $a 包含 $b,则返回 True。等效于 !(cont)

say (1,2,3 4;       # OUTPUT: «True␤» 
say (1,2,3!(cont) 2# OUTPUT: «False␤» 

中缀 (<),中缀 ⊂§

multi infix:«(<)»($a,$b --> Bool:D)

子集运算符.

如果 $a$b真子集,即 $a 的所有元素都是 $b 的元素,但 $a$b 小,则返回 True

say (1,2,3(<) (2,3,1); # OUTPUT: «False␤» 
say (2,3(<) (2,3,1);   # OUTPUT: «True␤» 
say 4  (1,2,3);         # OUTPUT: «False␤» 

中缀 §

multi infix:<>($a,$b --> Bool:D)

不为子集运算符.

如果 $a 不是 $b真子集,则返回 True。等效于 !(<)

say (1,2,3 (2,3,1); # OUTPUT: «True␤» 
say (2,3 (2,3,1);   # OUTPUT: «False␤» 
say 4 !(<) (1,2,3);    # OUTPUT: «True␤» 

中缀 (<=),中缀 ⊆§

multi infix:«(<=)»($a,$b --> Bool:D)

子集或等于运算符.

如果 $a$b 的 **子集**,则返回 True,即 $a 的所有元素都是 $b 的元素,但 $a 的大小小于或等于 $b

say (1,2,3(<=) (2,3,1); # OUTPUT: «True␤» 
say (2,3(<=) (2,3,1);   # OUTPUT: «True␤» 
say 4  (1,2,3);          # OUTPUT: «False␤» 

中缀 §

multi infix:<>($a,$b --> Bool:D)

不为子集也不等于运算符.

如果 $a **不是** $b 的 **子集**,则返回 True。等效于 !(<=)

say (1,2,3 (2,3,1); # OUTPUT: «False␤» 
say (2,3 (2,3,1);   # OUTPUT: «False␤» 
say 4 !(<=) (1,2,3);   # OUTPUT: «True␤» 

中缀 (>),中缀 §

multi infix:«(>)»($a,$b --> Bool:D)

超集运算符.

如果 $a$b 的 **真超集**,则返回 True,即 $b 的所有元素都是 $a 的元素,但 $a 的大小大于 $b

say (1,2,3(>) (2,3,1); # OUTPUT: «False␤» 
say (1,2,3(>) (2,3);   # OUTPUT: «True␤» 
say 4  (1,2,3);         # OUTPUT: «False␤» 

中缀 §

multi infix:<>($a,$b --> Bool:D)

不为超集运算符.

如果 $a **不是** $b 的 **真超集**,则返回 True。等效于 !(>)

say (1,2,3 (2,3,1); # OUTPUT: «True␤» 
say (1,2,3 (2,3);   # OUTPUT: «False␤» 
say 4 !(>) (1,2,3);    # OUTPUT: «True␤» 

中缀 (>=),中缀 §

multi infix:«(>=)»($a,$b --> Bool:D)

超集或等于运算符.

如果 $a$b 的 **超集**,则返回 True,即 $b 的所有元素都是 $a 的元素,但 $a 的大小大于或等于 $b

say (1,2,3(>=) (2,3,1); # OUTPUT: «True␤» 
say (1,2,3(>=) (2,3);   # OUTPUT: «True␤» 
say 4  (1,2,3);          # OUTPUT: «False␤» 

中缀 §

multi infix:<>($a,$b --> Bool:D)

不为超集也不等于运算符.

如果 $a **不是** $b 的 **超集**,则返回 True。等效于 !(>=)

say (1,2,3 (2,3,1); # OUTPUT: «False␤» 
say (1,2,3 (2,3);   # OUTPUT: «False␤» 
say 4 !(>=) (1,2,3);   # OUTPUT: «True␤» 

紧密 AND 优先级§

中缀 &&§

返回第一个在布尔上下文中计算为 False 的参数,否则返回最后一个参数。

请注意,这会短路,即如果其中一个参数计算为假值,则右侧的参数将永远不会被计算。

sub a { 1 }
sub b { 0 }
sub c { die "never called" };
say a() && b() && c();      # OUTPUT: «0␤»

紧密 OR 优先级§

中缀 ||§

返回第一个在布尔上下文中计算为 True 的参数,否则返回最后一个参数。

请注意,这会短路;即如果其中一个参数计算为真值,则不会计算其余参数。

sub a { 0 }
sub b { 1 }
sub c { die "never called" };
say a() || b() || c();      # OUTPUT: «1␤»

中缀 ^^§

短路异或。如果存在一个(且只有一个)真参数,则返回该参数。如果所有参数都为假,则返回最后一个参数。当多个参数为真时,返回 Nil

此运算符在以下意义上短路:它不会在第二个真结果之后计算任何参数。

say 0 ^^ 42;                             # OUTPUT: «42␤» 
say '' ^^ 0;                             # OUTPUT: «0␤» 
say 0 ^^ 42 ^^ 1 ^^ die "never called";  # OUTPUT: «Nil␤»

请注意,此运算符的语义可能与您假设的不同:中缀 ^^ 会翻转到它找到的第一个真值,然后在第二个真值之后永远翻转到 Nil,无论之后有多少个真值。(换句话说,它具有“查找唯一真值”的语义,而不是“布尔奇偶校验”的语义。)

中缀 //§

定义或运算符中缀 // 返回第一个已定义的操作数,否则返回最后一个操作数。短路。

say Any // 0 // 42;         # OUTPUT: «0␤»

中缀 min§

返回参数中最小的一个,由 cmp 语义确定。

my $foo = 42;
$foo min= 0   # read as: $foo decreases to 0

注意:在 2022.06 之前,在出现平局的情况下,&min 将返回具有该值的第一个参数,而 &[min] 将返回其 RHS。在 2022.06 之后,&[min] 在出现平局的情况下返回其 LHS,并且现在两者都返回与其列表关联性所规定的相同值。

say min 0False# OUTPUT: «0␤» 
say 0 min False;  # OUTPUT: «0␤» 
say min False0# OUTPUT: «False␤» 
say False min 0;  # OUTPUT: «False␤»

中缀 max§

返回根据 cmp 语义确定的最大参数。

my $foo = -42;
$foo max= 0   # read as: $foo increases to 0

注意: 在 2022.06 之前,在出现平局的情况下,&max 将返回具有该值的第一个参数,而 &[max] 将返回其 RHS。在 2022.06 之后,&[max] 在出现平局的情况下返回其 LHS,现在两者都返回与其列表关联性一致的相同值。

say max 0False# OUTPUT: «0␤» 
say 0 max False;  # OUTPUT: «0␤» 
say max False0# OUTPUT: «False␤» 
say False max 0;  # OUTPUT: «False␤»

中缀 minmax§

返回从最低值到最高值的 Range,由 cmp 语义确定。例如

# numeric comparison 
10 minmax 3;     # 3..10 
 
# string comparison 
'10' minmax '3'# "10".."3" 
'z' minmax 'k';  # "k".."z" 

如果最低值和最高值重合,则运算符将返回由相同值组成的 Range

1 minmax 1;  # 1..1 

当应用于 List 时,运算符将评估所有可用值中的最低值和最高值

(10,20,30minmax (0,11,22,33);       # 0..33 
('a','b','z'minmax ('c','d','w');   # "a".."z" 

类似地,当应用于 Hash 时,它将执行 cmp 方式比较

my %winner = points => 30misses => 10;
my %loser = points => 20misses => 10;
%winner cmp %loser;      # More 
%winner minmax %loser;
# ${:misses(10), :points(20)}..${:misses(10), :points(30)} 

条件运算符优先级§

中缀 ?? !!§

也称为三元条件运算符,$condition ?? $true !! $false 评估 $condition 并返回 ?? 后面的表达式,在本例中为 $true(如果为 True),否则评估并返回 !! 后面的表达式,在本例中为 $false

中缀 ff§

sub infix:<ff>(Mu $aMu $b)

也称为翻转运算符,将两个参数都与 $_ 进行比较(即 $_ ~~ $a$_ ~~ $b)。在左边的智能匹配为 True 之前,评估结果为 False,此时评估结果为 True,直到右边的智能匹配为 True

实际上,左边的参数是“开始”条件,右边的参数是“停止”条件。此构造通常用于仅提取特定部分的行。例如

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/;  # OUTPUT: «AB␤» 
}

如果您只想针对开始条件进行测试并且没有停止条件,则可以使用 * 作为

for <A B C D E> {
    say $_ if /C/ ff *;    # OUTPUT: «C␤D␤E␤» 
}

对于在开始条件成功后尝试 $_ 的停止条件的类似 sed 的版本,请参见 fff

此运算符无法重载,因为它由编译器特殊处理。

中缀 ^ff§

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

ff 的工作方式相同,只是它不会对匹配开始条件的项目(包括也匹配停止条件的项目)返回 True

比较

my @list = <X A B C Y>;
say $_ if /A/ ff /C/ for @list;    # OUTPUT: «A␤B␤C␤» 
say $_ if /A/ ^ff /C/ for @list;   # OUTPUT: «B␤C␤»

类似 sed 的版本可以在 ^fff 中找到。

此运算符无法重载,因为它由编译器特殊处理。

中缀 ff^§

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

ff 的工作方式相同,只是它不会对匹配停止条件的项目(包括首先匹配开始条件的项目)返回 True

my @list = <X A B C Y>;
say $_ if /A/ ff /C/ for @list;    # OUTPUT: «A␤B␤C␤» 
say $_ if /A/ ff^ /C/ for @list;   # OUTPUT: «A␤B␤»

类似 sed 的版本可以在 fff^ 中找到。

此运算符无法重载,因为它由编译器特殊处理。

中缀 ^ff^§

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

ff 的工作方式相同,只是它不会对匹配停止条件或开始条件(或两者)的项目返回 True

my @list = <X A B C Y>;
say $_ if /A/ ff /C/ for @list;    # OUTPUT: «A␤B␤C␤» 
say $_ if /A/ ^ff^ /C/ for @list;  # OUTPUT: «B␤»

类似 sed 的版本可以在 ^fff^ 中找到。

此运算符无法重载,因为它由编译器特殊处理。

中缀 fff§

sub infix:<fff>(Mu $aMu $b)

执行类似 sed 的翻转操作,其中它返回 False,直到左边的参数与 $_ 进行智能匹配,然后返回 True,直到右边的参数与 $_ 进行智能匹配。

ff 的工作方式类似,只是它每次调用只尝试一个参数。也就是说,如果 $_ 与左边的参数进行智能匹配,fff 不会随后尝试将相同的 $_ 与右边的参数进行匹配。

for <AB C D B E F> {
    say $_ if /A/ fff /B/;         # OUTPUT: «AB␤C␤D␤B␤» 
}

非类似 sed 的翻转(在成功地将左边的参数与 $_ 进行匹配后,将尝试将相同的 $_ 与右边的参数进行匹配并相应地执行操作)。参见 ff

此运算符无法重载,因为它由编译器特殊处理。

中缀 ^fff§

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

类似于 fff,但它不会对左边的参数匹配返回 true。

my @list = <X A B C Y>;
say $_ if /A/ fff /C/ for @list;   # OUTPUT: «A␤B␤C␤» 
say $_ if /A/ ^fff /C/ for @list;  # OUTPUT: «B␤C␤»

对于非 sed 版本,请参见 ^ff

此运算符无法重载,因为它由编译器特殊处理。

中缀 fff^§

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

类似于 fff,但它不会对右边的参数匹配返回 true。

my @list = <X A B C Y>;
say $_ if /A/ fff /C/ for @list;   # OUTPUT: «A␤B␤C␤» 
say $_ if /A/ fff^ /C/ for @list;  # OUTPUT: «A␤B␤»

对于非 sed 版本,请参见 ff^

此运算符无法重载,因为它由编译器特殊处理。

中缀 ^fff^§

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

类似于 fff,但它不会对左边或右边的参数匹配返回 true。

my @list = <X A B C Y>;
say $_ if /A/ fff /C/ for @list;   # OUTPUT: «A␤B␤C␤» 
say $_ if /A/ ^fff^ /C/ for @list# OUTPUT: «B␤»

对于非 sed 版本,请参见 ^ff^

此运算符无法重载,因为它由编译器特殊处理。

项目赋值优先级§

中缀 = (项目赋值)§

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

称为项目赋值运算符。它将右边表达式的值复制到左边 Scalar 容器中。

项目赋值运算符应与 列表赋值运算符 区分开来,后者使用相同的运算符符号 =,但优先级较低。= 符号左边的上下文决定了它是被解析为项目赋值还是列表赋值。有关这两种赋值类型的比较讨论,请参见 项目和列表赋值 部分。

中缀 =>§

sub infix:«=>»($keyMu $value --> Pair:D)

Pair 构造函数。

使用左边表达式作为键,右边表达式作为值,构造一个 Pair 对象。

请注意,=> 运算符在语法上是特殊情况,因为它允许在左边使用未引用的标识符。

my $p = => 1;
say $p.key;         # OUTPUT: «a␤» 
say $p.value;       # OUTPUT: «1␤»

参数列表中包含在左边使用未引用的标识符的 Pair 被解释为命名参数。

有关创建 Pair 对象的更多方法,请参见 术语语言文档

松散一元运算符优先级§

前缀 not§

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

在布尔上下文中评估其参数(因此会折叠 Junction),并对结果取反。请注意,not 很容易被误用。请参见 陷阱

前缀 so§

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

在布尔上下文中评估其参数(因此会折叠 Junction),并返回结果。

逗号运算符优先级§

中缀 ,§

sub infix:<,>(*@a --> List:Dis assoc<list>

从其参数构造一个高阶 Cool

my @list = :god('Þor'), ['is',"mighty"];
say @list;      # OUTPUT: «[god => Þor [is mighty]]␤» 
my %hash = :god('Þor'), :is("mighty");
say %hash.raku# OUTPUT: «{:god("Þor"), :is("mighty")}␤» 
my %a = :11a, :22b;
say %(%a:33x);  # OUTPUT: «{a => 11, b => 22, x => 33}␤»

在第一种情况下,它返回一个 List,在第二种情况下,由于参数是 Pair,它会构建一个 Hash

它还可以用于从其他变量构造变量,整理不同类型的元素,在这种情况下是 HashPair

my %features = %hash:wields("hammer");
say %features;  # OUTPUT: «{god => Þor, is => mighty, wields => hammer}␤» 

逗号在语法上也用作调用中参数的分隔符。

中缀 :§

用作参数分隔符,就像中缀 , 一样,并将它左边的参数标记为调用者。这将原本的函数调用变成了方法调用。

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

中缀 : 仅允许在非方法调用的第一个参数之后使用。在其他位置,它是一个语法错误。

列表中缀优先级§

中缀 Z§

sub infix:<Z>(**@lists --> Seq:Dis assoc<list>

名为 Zip 运算符 的运算符像拉链一样交织传递给 Z 的列表,从每个操作数中获取索引对应的元素。返回的 Seq 包含嵌套列表,每个列表都包含来自链中每个操作数的值。如果其中一个操作数过早地用完元素,则 zip 运算符将停止。

say (12 Z <a b c> Z <+ ->).raku;
# OUTPUT: «((1, "a", "+"), (2, "b", "-")).Seq␤» 
for <a b c> Z <1 2 3 4> -> [$l$r{
    say "$l:$r"
}
# OUTPUT: «a:1␤b:2␤c:3␤» 

Z 运算符也存在作为元运算符,在这种情况下,内部列表将被应用运算符到列表的结果值替换。

say 100200 Z+ 4223;             # OUTPUT: «(142 223)␤» 
say 1..3 Z~ <a b c> Z~ 'x' xx 3;    # OUTPUT: «(1ax 2bx 3cx)␤»

与任何其他中缀运算符一样,它可以在其全名下使用。

say infix:<Z>(<a b>,<c d>);             # OUTPUT: «((a c) (b d))␤» 

如果没有给出参数,它将返回一个空的 Seq

say infix:<Z>();                        # OUTPUT: «()␤» 

中缀 X§

multi infix:<X>(+lol:&with! --> Seq:D)
multi infix:<X>(+lol --> Seq:D)

从所有列表中创建一个交叉积,按顺序排列,以便最右边的元素变化最快,并返回一个 Seq

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 运算符也存在作为元运算符,在这种情况下,内部列表将被应用运算符到列表的结果值替换。

1..3 X~ <a b c> X~ 9
# produces (1a9 1b9 1c9 2a9 2b9 2c9 3a9 3b9 3c9)

§

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

名为 序列运算符 的运算符,可以写成 ...,以及变体 ...^^...^...^…^^…^…^,将按需生成(可能是惰性的)通用序列。此类序列属于 Seq 类型。

带有初始插入符号的运算符变体,^...^...^^…^…^,生成不包含初始元素的序列。

带有最终插入符号的运算符变体,...^^...^…^^…^,生成不包含最终元素的序列。

注意:变体 ^...^...^^…^…^ 从 2020.05 版本开始在 Rakudo 编译器中可用。

运算符的左侧指定初始元素;它可以在第一个元素或元素之后包含一个生成器。右侧将有一个端点,它可以是 Inf* 用于“无限”列表(即,惰性 列表,其元素仅按需生成),一个表达式,当 True 时将结束序列,或其他元素,例如 Junction

序列运算符使用必要的参数调用生成器。参数取自初始元素和已生成的元素。

* (Whatever)、Inf 的端点按需生成一个无限序列,默认生成器为 *.succ

say (1 ... *)[^5];  # OUTPUT: «(1 2 3 4 5)␤»

自定义生成器需要是 ... 运算符之前列表的最后一个元素。这个生成器接受两个参数,并生成前八个斐波那契数。

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

生成器也可以只接受一个参数。

say 5{ $_ * 2 } ... 40;                # OUTPUT: «5 10 20 40␤»

或者它可以使用 匿名状态变量 $ 在计算下一个元素时跳过序列中的一个位置。

say (111-> $a$b$ { $a + $b } … ∞)[3..10];
# OUTPUT: «(2 2 3 4 5 7 9 12)␤»

初始元素的数量必须至少与生成器的参数数量相同。

如果端点不是 *,则它会与每个生成的元素进行智能匹配,并且当智能匹配成功时,序列将终止。如果使用带有最终插入符号的序列运算符变体,则最终元素将被排除在序列之外,否则将被包含在内。

这允许你编写

say 11* + * ...^ *>= 100;
# OUTPUT: «(1 1 2 3 5 8 13 21 34 55 89)␤»

以生成所有小于 100 的斐波那契数。

... 运算符将初始值也视为“生成的元素”,因此它们也会针对端点进行检查。

my $end = 4;
say 124816 ... $end;
# OUTPUT: «(1 2 4)␤»

如果你没有提供生成器,序列运算符将尝试推断序列。在大多数情况下,这意味着使用默认的 *.succ*.pred,具体取决于端点如何比较。

say 1 ... 4;        # OUTPUT: «(1 2 3 4)␤» 
say 4 ... 1;        # OUTPUT: «(4 3 2 1)␤» 
say 1 ^... 4;       # OUTPUT: «(2 3 4)␤» 
say 1 ...^ 4;       # OUTPUT: «(1 2 3)␤» 
say 1 ^...^ 4;      # OUTPUT: «(2 3)␤» 
say 'a' ... 'e';    # OUTPUT: «(a b c d e)␤» 
say 'e' ... 'a';    # OUTPUT: «(e d c b a)␤»

但是,序列运算符会在某些特殊情况下推断出不同的序列。

如果你提供多个初始元素,并且所有初始元素都是数字,则序列运算符将尝试找到一个适合初始元素模式的算术或几何序列。

say 246 ... 12;     # OUTPUT: «(2 4 6 8 10 12)␤» 
say 124 ... 32;     # OUTPUT: «(1 2 4 8 16 32)␤» 
say 124 ^... 32;    # OUTPUT: «(2 4 8 16 32)␤» 
say 124 ^...^ 32;   # OUTPUT: «(2 4 8 16)␤»

如果你提供一个 Str 初始元素和一个 Str 最终元素,并且它们具有相同的字符数,则序列运算符将推断出一个所有字符串的序列,其中每个字母都 le 最终元素中对应位置的字母。

say 'aa' … 'cc';          # OUTPUT: «(aa ab ac ba bb bc ca cb cc)␤» 
# Which is the same as 
say 'a'..'c' X~ 'a'..'c'# OUTPUT: «(aa ab ac ba bb bc ca cb cc)␤»

列表前缀优先级§

中缀 = (列表赋值)§

列表赋值运算符通常将值从其右侧复制到其左侧的容器中。其确切语义由左侧容器类型决定。有关常见情况,请参阅 ArrayHash

列表赋值运算符应与 项目赋值运算符 区分,后者使用相同的运算符符号 = 但具有更高的优先级。= 符号左侧的上下文决定了它是解析为项目赋值还是列表赋值。有关两种赋值类型的比较讨论,请参阅 项目和列表赋值 部分。

中缀 :=§

绑定运算符。而 $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 都代表同一个对象。

如果变量或容器上存在类型约束,则将在运行时执行类型检查。如果失败,将抛出 X::TypeCheck::BindingType

请注意,:= 是一个编译时运算符。因此,它不能在运行时被引用,因此不能用作元运算符的参数。

中缀 ::=§

只读绑定运算符,尚未在 Rakudo 中实现。请参阅 infix :=

列表运算符 ...§

称为yada, yada, yada 运算符或存根运算符,如果它是例程或类型中唯一的语句,它将该例程或类型标记为存根(这在预声明类型和组合角色的上下文中很重要)。

如果执行 ... 语句,它将调用 fail,默认消息为 Stub code executed

此运算符可用于类的前向声明

class Foo {...}
class Bar {
    has Foo $.foo;
}
class Foo {
    say "This is a Foo object";
}

或例程,例如此 Sub

sub a() { ... }
say a;           # OUTPUT: «42␤» 
sub a() { 42 }

请注意,在这种情况下,它实际上不是必需的,并且在没有该前向声明的情况下它将以相同的方式工作。

列表运算符 !!!§

如果它是例程或类型中唯一的语句,它将该例程或类型标记为存根(这在预声明类型和组合角色的上下文中很重要)。

如果执行 !!! 语句,它将调用 die,默认消息为 Stub code executed

列表运算符 ???§

如果它是例程或类型中唯一的语句,它将该例程或类型标记为存根(这在预声明类型和组合角色的上下文中很重要)。

如果执行 ??? 语句,它将调用 warn,默认消息为 Stub code executed

归约运算符§

任何中缀运算符(非关联运算符除外)都可以用方括号括起来,在术语位置创建使用该运算符进行归约的列表运算符。

say [+123;      # 1 + 2 + 3 = 6 
my @a = (56);
say [*@a;           # 5 * 6 = 30

归约运算符与它们基于的运算符具有相同的结合性。

say [-] 432;      # 4-3-2 = (4-3)-2 = -1 
say [**432;     # 4**3**2 = 4**(3**2) = 262144

将 [+] 应用于单个元素将返回该元素

say [+42;           # OUTPUT: «42␤» 

松散 AND 优先级§

and§

infix && 相同,但优先级更低。

短路运算,返回第一个计算结果为 False 的操作数,否则返回最后一个操作数。请注意,and 很容易被误用,请参阅 陷阱

andthen§

andthen 运算符在遇到第一个 未定义 的参数时返回 Empty,否则返回最后一个参数。最后一个参数按原样返回,不会检查其是否已定义。短路运算。左侧的结果绑定到 $_ 用于右侧,或者作为参数传递,如果右侧是 Callable,其 count 必须为 01

此运算符的一个方便用法是将例程的返回值别名为 $_,并对其进行额外的操作,例如打印或将其返回给调用者。由于 andthen 运算符是短路运算,因此右侧的语句不会执行,除非左侧已定义(提示:Failure 从未定义,因此您可以使用此运算符来处理它们)。

sub load-data {
    rand  > .5 or return# simulated load data failure; return Nil 
    (rand > .3 ?? 'error' !! 'good data'xx 10 # our loaded data 
}
load-data.first: /good/ andthen say "$_ is good";
# OUTPUT: «(good data is good)␤» 
 
load-data() andthen .return# return loaded data, if it's defined 
die "Failed to load data!!";

上面的示例将仅在子例程返回任何与 /good/ 匹配的项目时打印 good data is good,并且除非加载数据返回一个已定义的值,否则将终止。别名行为使我们能够将值通过运算符传递。

andthen 运算符与 with 语句修饰符 密切相关,一些编译器将 with 编译为 andthen,这意味着这两行具有等效的行为

.say with 42;
42 andthen .say;

notandthen§

notandthen 运算符在遇到第一个 已定义 的参数时返回 Empty,否则返回最后一个参数。最后一个参数按原样返回,不会检查其是否已定义。短路运算。左侧的结果绑定到 $_ 用于右侧,或者作为参数传递,如果右侧是 Callable,其 count 必须为 01

乍一看,notandthen 似乎与 orelse 运算符相同。区别很细微:notandthen 在遇到 已定义 的项目(不是最后一个项目)时返回 Empty,而 orelse 返回该项目。换句话说,notandthen 是一种在项目未定义时采取行动的方式,而 orelse 是一种获取第一个已定义项目的方式。

sub all-sensors-down     { [notandthen|@_True             }
sub first-working-sensor { [orelse]     |@_'default sensor' }
 
all-sensors-down NilNilNil
  and say 'OMG! All sensors are down!'# OUTPUT:«OMG! All sensors are down!␤» 
say first-working-sensor NilNilNil# OUTPUT:«default sensor␤» 
 
all-sensors-down Nil42Nil
  and say 'OMG! All sensors are down!'# No output 
say first-working-sensor Nil42Nil;  # OUTPUT:«42␤» 

notandthen 运算符与 without 语句修饰符 密切相关,一些编译器将 without 编译为 notandthen,这意味着这两行具有等效的行为

sub good-things { fail }
 
'boo'.say without good-things;
good-things() notandthen 'boo'.say;

松散 OR 优先级§

infix or§

infix || 相同,但优先级更低。

返回第一个在布尔上下文中计算结果为 True 的参数,否则返回最后一个参数,它是短路运算。请注意,or 很容易被误用。请参阅 陷阱

infix orelse§

orelse 运算符类似于 infix //,但优先级更低,并且具有 $_ 别名。

返回第一个定义的实参,否则返回最后一个实参。最后一个实参按原样返回,不会检查其是否已定义。短路。左侧的结果绑定到$_,用于右侧,或者作为实参传递,如果右侧是Callable,其count必须为01

此运算符对于处理由例程返回的Failure很有用,因为预期值通常是defined,而Failure永远不会是。

sub meows { ++$ < 4 ?? fail 'out of meows!' !! '🐱' }
 
sub meows-processor1 { meows() orelse .return } # return handled Failure 
sub meows-processor2 { meows() orelse fail $_ } # return re-armed Failure 
sub meows-processor3 {
    # Use non-Failure output, or else print a message that stuff's wrong 
    meows() andthen .say orelse something's wrong.say;
}
 
say "{.^name}{.handled}"  # OUTPUT: «Failure, True␤» 
    given meows-processor1;
say "{.^name}{.handled}"  # OUTPUT: «Failure, False␤» 
    given meows-processor2;
meows-processor3;           # OUTPUT: «something's wrong␤» 
meows-processor3;           # OUTPUT: «🐱␤»

中缀 xor§

中缀 ^^相同,但优先级较低。

返回在布尔上下文中计算为True的操作数,当且仅当另一个操作数在布尔上下文中计算为False时。如果两个操作数都计算为False,则返回最后一个实参。如果两个操作数都计算为True,则返回Nil.

在链式操作中,返回计算为True的操作数,当且仅当存在一个这样的操作数。如果多个操作数为真,则在评估第二个操作数后短路并返回Nil。如果所有操作数都为假,则返回最后一个操作数。

排序器优先级§

中缀 ==>§

feed运算符获取左侧的结果并将其作为最后一个参数传递给下一个(右侧)例程。

my @array = (12345);
@array ==> sum() ==> say();   # OUTPUT: «15␤»

上面的这个简单示例等效于编写

my @array = (12345);
say(sum(@array));             # OUTPUT: «15␤»

或者如果使用方法

my @array = (12345);
@array.sum.say;               # OUTPUT: «15␤»

优先级非常低,因此您需要使用括号来分配结果,或者您甚至可以使用另一个 feed 运算符!在例程/方法接受单个实参或第一个实参是块的情况下,通常需要使用括号调用(尽管对于最后一个例程/方法不需要这样做)。

这种“传统”结构,从下到上阅读,最后两行创建将要处理的数据结构

my @fractions = <TWO THREE FOUR FIVE SEVEN> »~» " " X~ <FIFTHS SIXTHS EIGHTHS>;
my @result = map { .uniparse },                    # (3) Converts to unicode 
    grep { .uniparse },                            # (2) Checks if it parses 
    map{"VULGAR FRACTION " ~ $^þ }@fractions); # (1) Adds string to input 
 
# @result is [⅖ ⅗ ⅜ ⅘ ⅚ ⅝ ⅞]

现在我们使用 feed 运算符(从左到右)以及括号,从上到下阅读

my @result = (
    <TWO THREE FOUR FIVE SEVEN> »~» " " X~ <FIFTHS SIXTHS EIGHTHS> # (1) Input 
    ==> map{"VULGAR FRACTION " ~ $^þ } )                         # (2) Converts to Unicode name 
    ==> grep({ .uniparse })                                        # (3) Filters only real names 
    ==> map{ .uniparse} );                                       # (4) Converts to unicode 
);

为了说明,方法链式操作等效,从上到下阅读,使用与上面相同的顺序

my @result = ( <TWO THREE FOUR FIVE SEVEN> »~» " " X~ <FIFTHS SIXTHS EIGHTHS>)
    .map{"VULGAR FRACTION " ~ $^þ } )
    .grep({ .uniparse })
    .map({ .uniparse });

虽然在这种特定情况下结果相同,但 feed 运算符==>更清楚地显示了意图,箭头指向数据流的方向。要分配而无需使用括号,请使用另一个 feed 运算符

<people of earth>
    ==> map({ .tc })
    ==> grep /<[PE]>/
    ==> sort()
    ==> my @result;

捕获部分结果可能很有用,但是,与向左 feed 运算符不同,它确实需要括号或分号

<people of earth>
    ==> map({ .tc })
    ==> my @caps@caps   # also could wrap in parentheses: (my @caps) 
    ==> grep /<[PE]>/
    ==> sort()
    ==> my @result;

feed 运算符允许您从例程和无关数据上的方法结果构建类似于方法链式操作的模式。在方法链式操作中,您仅限于数据上可用或先前方法调用结果的方法。使用 feed 运算符,该限制消失了。生成的代码也可以被认为比跨多行断开的多个方法调用更易读。

注意:将来,此运算符将发生一些变化,因为它将获得并行运行列表操作的能力。它将强制执行左侧操作数可以作为闭包(可以克隆并在子线程中运行)进行封闭。

中缀 <==§

leftward feed运算符获取右侧的结果并将其作为最后一个参数传递给前面的(左侧)例程。这阐明了一系列列表操作函数的从右到左的数据流。

# Traditional structure, read bottom-to-top 
my @result =
    sort                   # (4) Sort, result is <Earth People> 
    grep { /<[PE]>/ },     # (3) Look for P or E 
    map { .tc },           # (2) Capitalize the words 
    <people of earth>;     # (1) Start with the input 
 
# Feed (right-to-left) with parentheses, read bottom-to-top 
my @result = (
    sort()                 # (4) Sort, result is <Earth People> 
    <== grep({ /<[PE]>/ }# (3) Look for P or E 
    <== map({ .tc })       # (2) Capitalize the words 
    <== <people of earth>  # (1) Start with the input 
);
 
# To assign without parentheses, use another feed operator 
my @result
    <== sort()              # (4) Sort, result is <Earth People> 
    <== grep({ /<[PE]>/ })  # (3) Look for P or E 
    <== map({ .tc })        # (2) Capitalize the words 
    <== <people of earth>;  # (1) Start with the input 
 
# It can be useful to capture a partial result 
my @result
    <== sort()
    <== grep({ /<[PE]>/ })
    <== my @caps            # unlike ==>there's no need for additional statement
    <== map({ .tc })
    <== <people of earth>;

与向右 feed 运算符不同,结果不能与方法链式操作紧密映射。但是,与上面每个参数都用一行分隔的传统结构相比,生成的代码比逗号更具演示性。向左 feed 运算符还允许您“进入”语句并捕获中间结果,这对于调试或获取该结果并创建最终结果的另一个变体非常有用。

注意:将来,此运算符将发生一些变化,因为它将获得并行运行列表操作的能力。它将强制执行右侧操作数可以作为闭包(可以克隆并在子线程中运行)进行封闭。

标识§

通常,中缀运算符可以应用于单个或零个元素而不会产生错误,通常是在reduce操作的上下文中。

say [-] ()  # OUTPUT: «0␤»

设计文档规定,这应该返回一个单位值,并且每个运算符都必须指定一个单位值 一般来说,返回的单位值应该是直观的。但是,以下表格指定了如何在 Raku 中为运算符类定义单位值,这对应于语言定义的类型和运算符中上述定义中的表格。

运算符类单位值
相等
算术 +0
算术 *1
比较
按位0
字符串''
集合空集或等效值
或类布尔值
与类布尔值

例如,空列表的并集将返回一个空集。

say [];  # OUTPUT: «Set()␤»

这仅适用于空或 0 始终是有效操作数的运算符。例如,将其应用于除法将导致异常。

say [%] ();  # OUTPUT: «(exit code 1) No zero-arg meaning for infix:<%>␤»