语法

Raku 借用了人类语言中的许多概念。考虑到它是由语言学家设计的,这并不奇怪。

它重用不同语境中的共同元素,具有名词(术语)和动词(运算符)的概念,是上下文敏感的(在日常意义上,不一定在计算机科学解释中),因此符号可以具有不同的含义取决于名词或动词是否是预期的。

它也是自同步的,因此解析器可以检测大多数常见错误并提供良好的错误消息。

词法约定

Raku 代码是 Unicode 文本。当前的实现支持 UTF-8 作为输入编码。

也参阅 Unicode versus ASCII symbols.

自由形式

Raku 代码也是自由格式的,从某种意义上说,你可以自由选择你使用的空格量,尽管在某些情况下,空格的存在与否具有意义。

所以你可以写

if True {
    say "Hello";
}

    if True {
say "Hello"; # Bad indentation intended 
        }

if True { say "Hello" }

或者甚至

if True {say "Hello"}

虽然你不能省略任何剩余的空白。

Unspace

在编译器不允许空格的许多地方,只要用反斜杠引用,就可以使用任意数量的空格。不支持 token 中的空格。当编译器生成行号时,未空格的换行仍然计算。用于非空格的用例是后缀运算符和例程参数列表的分离。

sub alignment(+@l) { +@l };
sub long-name-alignment(+@l) { +@l };
alignment\         (1,2,3,4).say;
long-name-alignment(3,5)\   .say;
say Inf+Inf\i;

在这种情况下,我们的目的是让 . 两个语句以及括号都对齐,所以我们在用于填充的空格之前加上 \

用分号分割语句

Raku 程序是一组由分号 ; 分割的语句。

say "Hello";
say "world";

最后一个语句之后(或在块内的最终语句之后)的分号是可选的。

say "Hello";
say "world"
if True {
    say "Hello"
}
say "world"

隐式分隔符规则(对于以块结尾的语句)

以裸块结尾的完整语句可以省略尾随分号,如果同一行上没有其他语句跟随块的结束大括号 }。 这称为“隐式分隔符规则”。例如,您不需要在 if 语句块之后写一个分号,如上所示,以及下面所示。

if True { say "Hello" }
say "world";

但是,需要使用分号将块与同一行中的尾随语句分开。

if True { say "Hello" }; say "world";
#                     ^^^ this ; is required 

此隐式语句分隔符规则除了控制语句之外还以其他方式应用,可能以裸块结束。例如,结合冒号:方法调用的语法。

my @names = <Foo Bar Baz>;
my @upper-case-names = @names.map: { .uc }    # OUTPUT: [FOO BAR BAZ] 

对于属于同一 if/elsif/else(或类似)构造的一系列块,隐式分隔符规则仅适用于该系列的最后一个块的末尾。这三个是等价的:

if True { say "Hello" } else { say "Goodbye" }; say "world";
#                                            ^^^ this ; is required 
if True { say "Hello" } else { say "Goodbye" } # <- implied statement separator 
say "world";
if True { say "Hello" }   # still in the middle of an if/else statement 
else    { say "Goodbye" } # <- no semicolon required because it ends in a block 
                          #    without trailing statements in the same line 
say "world";

注释

注释是程序文本的一部分,仅供人类读者阅读; Raku 编译器不会将它们当作程序文本。

在缺少或存在空白消除可能的解析的地方,注释计为空格。

单行注释

Raku 中最常见的注释形式以单个哈希字符 # 开头,直到该行的结尾。

if $age > 250 {     # catch obvious outliers 
    # this is another comment! 
    die "That doesn't look right"
}

多行 / 嵌套注释

多行和嵌入式注释以井号字符开头,然后是反引号,然后是一些开口括号字符,并以匹配的闭合括号字符结束。内容不仅可以跨越多行,还可以嵌入内联。

if #`( why would I ever write an inline comment here? ) True {
    say "something stupid";
}

这些注释可以扩展到多行

#`[
And this is how a multi would work.
That says why we do what we do below.
]
say "No more";

注释中的大括号可以嵌套,因此在 #{ a { b } c }, 中,注释一直持续到字符串的最后。 您也可以使用多个花括号,例如 #{{ double-curly-brace }},这可能有助于消除嵌套分隔符的歧义。 您可以在表达式中嵌入这些注释,只要不将它们插入关键字或标识符的中间即可。

Pod 注释

Pod 语法可用于多行注释

say "this is code";
 
=begin comment
 
Here are several
lines
of comment
 
=end comment
 
say 'code again';

标识符

标识符是语法构建块,可用于为实体/对象赋予名称,例如常量,变量(例如标量)和例程(例如,Subs 和方法)。在变量名中,任何sigil(和twigil)都在标识符之前,并且不形成其一部分。

constant c = 299792458;     # identifier "c" names an Int 
my $a = 123;                # identifier "a" in the name "$a" of a Scalar 
sub hello { say "Hello!" }; # identifier "hello" names a Sub 

标识符有不同的形式:普通标识符,扩展标识符和复合标识符。

普通标识符

普通标识符由前导字母字符组成,后面可以跟着一个或多个字母数字字符。它也可能包含单独的,嵌入的撇号 ' 和/或连字符 -, 前提是下一个字符每次都是字母。

“字母”和“字母数字”的定义包括适当的 Unicode 字符。哪些字符“合适”取决于实现。在 Rakudo/MoarVM Raku 实现中,字母字符包括具有 Unicode 通用类别值 Letter(L) 和下划线 _ 的字符。字母数字字符还包括具有 Unicode 通用类别值编号,十进制数字(Nd) 的字符。

# valid ordinary identifiers: 
x
_snake_oil
something-longer
with-numbers1234
don't-do-that
piece_of_π
駱駝道              # "Rakuda-dō", Japanese for "Way of the camel" 
# invalid ordinary identifiers: 
42                 # identifier does not start with alphabetic character 
with-numbers1234-5 # embedded hyphen not followed by alphabetic character 
is-prime?          # question mark is not alphanumeric 
x²                 # superscript 2 is not alphanumeric (explained above) 

扩展标识符

使名称包含普通标识符中不允许的字符通常很方便。用例包括一组实体共享一个共同的“短”名称但仍需要单独识别其每个元素的情况。例如,您可以使用短名称为 Dog 的模块,而其长名称包括其命名所有权和版本号:

Dog:auth<Somebody>:ver<1.0>  # long module names including author and version 
Dog:auth<Somebody>:ver<2.0>
 
use Dog:auth<Somebody>:ver<2.0>;
# Selection of second module causes its full name to be aliased to the 
# short name for the rest of # the lexical scope, allowing a declaration 
# like this. 
my Dog $spot .= new("woof");

类似地,运算符集在各种语法类别中一起工作,其名称如 prefix,infix 和 postfix。这些运算符的官方名称通常包含从普通标识符中排除的字符。长名称是扩展标识符的构成,包括这个句法类别;短名称将包含在定义中的引号中:

infix:<+>                 # the official name of the operator in $a + $b 
infix:<*>                 # the official name of the operator in $a * $b 
infix:«<=»                # the official name of the operator in $a <= $b 

对于所有此类用途,您可以将一个或多个冒号分隔的字符串附加到普通标识符,以创建所谓的扩展标识符。 附加到标识符(即后缀位置)时,此冒号分隔的字符串会生成该标识符的唯一变体。

这些字符串的格式为 :key<value>,其中 key 或 value 是可选的; 也就是说,在将它与常规标识符分开的冒号之后,将存在一个键和/或引用包围结构,例如 <>,«» 或 [’ ‘],它引用一个或多个任意字符值。[1]

# exemplary valid extended identifiers: 
postfix:<²>               # the official long name of the operator in $x² 
WOW:That'sAwesome
WOW:That's<<🆒>>
party:sweet<16>
 
# exemplary invalid extended identifiers: 
party:16<sweet>           # 16 is not an ordinary identifier 
party:16sweet
party:!a                  # ...and neither is !a 
party:$a                  # ...nor $a 

在扩展标识符中,后缀字符串被视为名称的组成部分,因此 infix:<+>infix:<-> 是两个不同的运算符。但是,使用的包围字符不算作其中的一部分;只有引用的数据很重要。所以这些都是同一个名字:

infix:<+>
infix:<<+>>
infix:«+»
infix:['+']
infix:('+')

同样,所有这些都有效:

my $foo:bar<baz> = 'quux';
say $foo:bar«baz»;                               # OUTPUT: «quux␤» 
my $take-me:<home> = 'Where the glory has no end';
say $take-me:['home'];                           # OUTPUT: «Where [...]␤» 
my $foo:bar<2> = 5;
say $foo:bar(1+1);                               # OUTPUT: «5␤» 

如果扩展标识符包含两个或更多个冒号对,则它们的顺序通常很重要:

my $a:b<c>:d<e> = 100;
my $a:d<e>:b<c> = 200;
say $a:b<c>:d<e>;               # OUTPUT: «100␤», NOT: «200␤» 

此规则的一个例外是模块版本控制;所以这些标识符有效地命名相同的模块:

use ThatModule:auth<Somebody>:ver<2.7.18.28.18>
use ThatModule:ver<2.7.18.28.18>:auth<Somebody>

此外,扩展标识符支持编译时插值;这需要使用常量作为插值:

constant $c = 42;  # Constant binds to Int; $-sigil enables interpolation 
my $a:foo<42> = "answer";
say $a:foo«$c»;    # OUTPUT: «answer␤» 

虽然引用包围结构在标识符的上下文中通常是可互换的,但它们并不相同。特别是,尖括号 <>(模仿单引号插值特征)不能用于常量名称的插值。

constant $what = 'are';
my @we:<are>= <the champions>;
say @we:«$what»;     # OUTPUT: «[the champions]␤» 
say @we:<$what>;
# Compilation error: Variable '@we:<$what>' is not declared 

组合标识符

复合标识符是由两个或多个普通和/或扩展标识符组成的标识符,这些标识符通过双冒号 :: 彼此分开。

双冒号 :: 被称为命名空间分隔符或包分隔符,它在名称中阐明了它的语义功能:强制将名称的前一部分视为包名/命名空间,名称的后续部分通过该包/命名空间位于:

module MyModule {               # declare a module package 
    our $var = "Hello";         # declare package-scoped variable 
}
say $MyModule::var              # OUTPUT: «Hello␤» 

在上面的示例中,MyModule::var 是一个复合标识符,由包名称标识符 MyModule 和变量名称 var 的标识符部分组成。加在一块, $MyModule::var 通常被称为包限定名。

使用双冒号分隔标识符会导致最右边的名称插入到现有包(参见上面的示例)或自动创建的包中:

my $foo::bar = 1;
say OUR::.keys;           # OUTPUT: «(foo)␤» 
say OUR::foo.HOW          # OUTPUT: «Raku::Metamodel::PackageHOW.new␤» 

最后几行显示了如何自动创建 foo 包,作为该命名空间中变量的存放。

双冒号语法允许使用 ::($expr) 将字符串运行时插入到包或变量名中,您通常会在其中放置包或变量名:

my $buz = "quux";
my $bur::quux = 7;
say $bur::($buz);               # OUTPUT: «7␤» 

项 term:<>

您可以使用 term:<> 来引入新的项,这对于引入违反常规标识符规则的常量非常方便:

use Test; plan 1; constant &term:<👍> = &ok.assuming(True);
👍
# OUTPUT: «1..1␤ok 1 - ␤» 

但是项不必是常量:您也可以将它们用于不带任何参数的函数,并强制解析器在它们之后期望运算符。例如:

sub term:<dice> { (1..6).pick };
say dice + dice;

可以打印 2 到 12 之间的任何数字。

相反,我们已经声明 dice 为常规子例程

sub dice() {(1...6).pick }

表达式 dice + dice 将被解析为 dice(+(dice())),导致错误,因为子 dice 需要零个参数。

语句和表达式

Raku 程序由一组组成。语句的一个特例是表达式,它返回一个值。例如, if True { say 42 } 在语法上是一个语句,而不是一个表达式,而 1 + 2 是一个表达式(因此也是一个语句)。

do 前缀将语句转换为表达式。所以虽然

my $x = if True { 42 };     # Syntax error! 

是一个错误,

my $x = do if True { 42 };

if 语句(此处为 42)的返回值赋给变量 $x

项是基本名词,可选地与运算符一起形成表达式。项的示例是变量($x),诸如类型名称(Int),字面量(42),声明(sub f() { })和调用(f())之类的裸字。

例如,在表达式 2 * $salary 中,2$salary 是两个项(整数字面量和变量)。

变量

变量通常以称为 sigil 的特殊字符开头,后跟一个标识符。必须先声明变量才能使用它们。

# declaration: 
my $number = 21;
# usage: 
say $number * 2;

有关更多详细信息,请参阅变量文档。

裸字 (常量,类型名)

预先声明的标识符可以是它们自己的术语。这些通常是类型名称或常量,但也是术语 self,它指的是调用方法的对象(请参阅对象)和无符号变量:

say Int;                # OUTPUT: «(Int)␤» 
#   ^^^ type name (built in) 
 
constant answer = 42;
say answer;
#   ^^^^^^ constant 
 
class Foo {
    method type-name {
        self.^name;
      # ^^^^ built-in term 'self' 
    }
}
say Foo.type-name;     # OUTPUT: «Foo␤» 
#   ^^^ type name 

包和限定名

命名实体(如变量,常量,类,模块或子)是命名空间的一部分。名称的嵌套部分使用 :: 来分隔层次结构。一些例子:

$foo                # simple identifiers 
$Foo::Bar::baz      # compound identifiers separated by :: 
$Foo::($bar)::baz   # compound identifiers that perform interpolations 
Foo::Bar::bob(23)   # function invocation given qualified name 

有关更多详细信息,请参阅包中的文档。

字面量

字面量是源代码中常量值的表示。 Raku 具有几种内置类型的字面量,如字符串,几种数字类型,pair 对儿等等。

字符串字面量

字符串字面量用引号括起来:

say 'a string literal';
say "a string literal\nthat interprets escape sequences";

请参阅引用以获取更多选项,包括转义引用 q。 Raku 在字面量中使用标准转义字符 \a \b \t \n \f \r \e, 与设计文档中指定的 ASCII 转义码具有相同的含义。

say "🔔\a";  # OUTPUT: «🔔␇␤» 

数字字面量

数字字面量通常用十进制表示(除非前缀为 0x(十六进制,基数为16),0o(八进制,基数为8)或 0b(二进制,基数为2),否则可以通过前缀0d逐字地使用(如果需要,可以使用前缀 0d)。 )或状语符号中的显式基数,如 :16<A0> 另有说明。与其他编程语言不同,前导零不表示基数 8;而是发出编译时警告。

在所有字面量格式中,你可以使用下划线来分组数字;他们没有任何语义信息;以下字面量都计算为相同的数字:

1000000
1_000_000
10_00000
100_00_00
Int 字面量

整数默认为有符号十进制的,但您可以使用其他基数。有关详细信息,请参阅 Int。

# actually not a literal, but unary - operator applied to numeric literal 2 
-2
12345
0xBEEF      # base 16 
0o755       # base 8 
:3<1201>    # arbitrary base, here base 3 
Rat 字面量

Rat 字面量(有理数)非常常见,取代许多其他语言中的小数或浮点数。整除也会产生 Rat。

1.0
3.14159
-2.5        # Not actually a literal, but still a Rat 
:3<21.0012> # Base 3 rational 
⅔
2/3         # Not actually a literal, but still a Rat 
Num 字面量

e 产生浮点数后,使用整数指数到十进制的科学记数法:

1e0
6.022e23
1e-9
-2e48
2e2.5       # error 
Complex 字面量

复数可以写为虚数(只是附加后缀 i 的有理数),也可以是实数和虚数之和:

1+2i
6.123e5i    # note that this is 6.123e5 * i, not 6.123 * 10 ** (5i) 

Pair 字面量

对由键和值组成,构造它们有两种基本形式:key => 'value':key('value')

Arrow pairs

箭头对可以有一个表达式,一个字符串字面量或一个“裸标识符”,这是一个普通标识符语法的字符串,左侧不需要引号:

like-an-identifier-ain't-it => 42
"key" => 42
('a' ~ 'b') => 1
副词对儿 (colon pairs)

没有显式值的简短形式:

my $thing = 42;
:$thing                 # same as  thing => $thing 
:thing                  # same as  thing => True 
:!thing                 # same as  thing => False 

变量形式也适用于其他符号,例如::&callback:@elements。如果值是数字字面量,它也可以用这种简短形式表示:

:42thing            # same as  thing => 42 
:٤٢thing            # same as  thing => 42 

如果您使用其他字母,则此顺序将被反转:

:٤٢ث              # same as   ث => ٤٢ 

thaa 字母在数字之前。

具有显式值的长形式:

:thing($value)              # same as  thing => $value 
:thing<quoted list>         # same as  thing => <quoted list> 
:thing['some', 'values']    # same as  thing => ['some', 'values'] 
:thing{a => 'b'}            # same as  thing => { a => 'b' } 

Boolean 字面量

True 和 False 是 Boolean 字面量; 他们始终是首字母大写的。

Array 字面量

一对方括号可以围绕表达式以形成逐项数组字面量; 通常在里面有一个以逗号分隔的列表:

say ['a', 'b', 42].join(' ');   # OUTPUT: «a b 42␤» 
#   ^^^^^^^^^^^^^^ Array constructor 

如果构造函数被赋予单个 Iterable,它将克隆并展平它。如果你想要一个只有 1 个 Iterable 元素的数组,请确保在它之后使用逗号:

my @a = 1, 2;
say [@a].perl;  # OUTPUT: «[1, 2]␤» 
say [@a,].perl; # OUTPUT: «[[1, 2],]␤» 

Array 构造函数不会展平其他类型的内容。使用 Slip 前缀运算符(|)展平所需项:

my @a = 1, 2;
say [@a, 3, 4].perl;  # OUTPUT: «[[1, 2], 3, 4]␤» 
say [|@a, 3, 4].perl; # OUTPUT: «[1, 2, 3, 4]␤» 

Hash 字面量

一个前导的关联符号和一对括号 %( ) 可以包围一对列表以形成一个哈希字面量; 通常在里面有一个以逗号分隔的 Pairs 列表。如果使用非 pair 对,则假定它是一个键,下一个元素是值。大多数情况下,它与简单的箭头对一起使用。

say %( a => 3, b => 23, :foo, :dog<cat>, "french", "fries" );
# OUTPUT: «a => 3, b => 23, dog => cat, foo => True, french => fries␤» 
 
say %(a => 73, foo => "fish").keys.join(" ");   # OUTPUT: «a foo␤» 
#   ^^^^^^^^^^^^^^^^^^^^^^^^^ Hash constructor 

当赋值给左侧的 % sigiled 变量时,右侧 Pairs 周围的符号和括号是可选的。

my %ages = fred => 23, jean => 87, ann => 4;

默认情况下, %( ) 中的键被强制为字符串。要使用非字符串键组合散列,请使用带有冒号前缀的花括号分隔符 :{}

my $when = :{ (now) => "Instant", (DateTime.now) => "DateTime" };

请注意,将对象作为键,您不能将非字符串键作为字符串访问:

say :{ -1 => 41, 0 => 42, 1 => 43 }<0>;  # OUTPUT: «(Any)␤» 
say :{ -1 => 41, 0 => 42, 1 => 43 }{0};  # OUTPUT: «42␤» 

Regex 字面量

使用 /foo/ 等斜杠声明正则表达式。请注意,此 // 语法是完整的 rx// 语法的简写。

/foo/          # Short version 
rx/foo/        # Longer version 
Q :regex /foo/ # Even longer version
 
my $r = /foo/; # Regexes can be assigned to variables

签名字面量

除了 sub 和块声明中的典型用法之外,签名可以单独用于模式匹配。从冒号开始声明独立签名:

say "match!" if 5, "fish" ~~ :(Int, Str); # OUTPUT: «match!␤» 
 
my $sig = :(Int $a, Str);
say "match!" if (5, "fish") ~~ $sig; # OUTPUT: «match!␤» 
 
given "foo", 42 {
  when :(Str, Str) { "This won't match" }
  when :(Str, Int $n where $n > 20) { "This will!" }
}

有关签名的更多信息,请参阅签名文档。

声明

变量声明

my $x;                          # simple lexical variable 
my $x = 7;                      # initialize the variable 
my Int $x = 7;                  # declare the type 
my Int:D $x = 7;                # specify that the value must be defined (not undef) 
my Int $x where { $_ > 3 } = 7; # constrain the value based on a function 
my Int $x where * > 3 = 7;      # same constraint, but using Whatever shorthand 

有关其他作用域的更多详细信息,请参阅变量声明符和作用域(ourhas)。

子例程声明

# The signature is optional 
sub foo { say "Hello!" }
 
sub say-hello($to-whom) { say "Hello $to-whom!" }

您还可以将子例程赋值给变量。

my &f = sub { say "Hello!" } # Un-named sub 
my &f = -> { say "Hello!" }  # Lambda style syntax. The & sigil indicates the variable holds a function 
my $f = -> { say "Hello!" }  # Functions can also be put into scalars 

包, 模块, 类, 角色 和 Grammar 声明

有几种类型的包,每种类型都使用关键字,名称,一些可选特征以及子例程,方法或规则体声明。

package P { }
 
module M { }
 
class C { }
 
role R { }
 
grammar G { }

可以在单个文件中声明多个包。但是,您可以在文件的开头声明一个单元包(仅在注释或 use 语句之前),并且该文件的其余部分将被视为包的主体。在这种情况下,不需要花括号。

unit module M;
# ... stuff goes here instead of in {}'s 

多重分派的声明

另请参见多重分派。

可以使用多个签名声明同名子例程。

multi sub foo() { say "Hello!" }
multi sub foo($name) { say "Hello $name!" }

在类里面, 你还可以声明多重分派方法。

multi method greet { }
multi method greet(Str $name) { }

子例程调用

子程序使用关键字 sub 创建,后跟可选名称,可选签名和代码块。子例程是词法作用域的,因此如果在声明时指定了名称,则可以在词法作用域中使用相同的名称来调用子例程。子例程是 Sub 类型的实例,可以赋值给任何容器。

foo;   # Invoke the function foo with no arguments 
foo(); # Invoke the function foo with no arguments 
&f();  # Invoke &f, which contains a function 
&f.(); # Same as above, needed to make the following work 
my @functions = ({say 1}, {say 2}, {say 3});
@functions>>.(); # hyper method call operator 

当在类中声明时,子例程被命名为“方法”:方法是针对对象(即,类实例)调用的子例程。在方法中,特殊变量 self 包含对象实例(请参阅方法)。

# Method invocation. Object (instance) is $person, method is set-name-age 
$person.set-name-age('jane', 98);   # Most common way 
$person.set-name-age: 'jane', 98;   # Precedence drop 
set-name-age($person: 'jane', 98);  # Invocant marker 
set-name-age $person: 'jane', 98;   # Indirect invocation 

有关更多信息,请参阅函数。

优先级下降

在方法调用的情况下(即,在针对类实例调用子例程时),可以应用由冒号标识的优先级下降:在方法名称之后和参数列表之前。参数列表优先于方法调用,另一方面“降低”其优先级。为了更好地理解,请考虑以下简单示例(仅添加额外空格以对齐方法调用):

my $band = 'Foo Fighters';
say $band.substr( 0, 3 ) .substr( 0, 1 ); # F 
say $band.substr: 0, 3   .substr( 0, 1 ); # Foo 

在第二种方法调用中,最右边的 substr 应用于“3”,而不是最左边的 substr 的结果,另一方面,它产生优先级最右边的 substr。

运算符

有关详细信息,请参阅运算符。

运算符是具有更多符号重和可组合语法的函数。与其他函数一样,运算符可以进行多重分派以允许特定于上下文的使用。

运算符有五种类型(排列),每种类型都有一个或两个参数。

++$x           # prefix, operator comes before single input 
5 + 3          # infix, operator is between two inputs 
$x++           # postfix, operator is after single input 
<the blue sky> # circumfix, operator surrounds single input 
%foo<bar>      # postcircumfix, operator comes after first input and surrounds second 

元运算符

运算符可以组合。一个常见的例子是将中缀(二元)运算符与赋值相结合。您可以将赋值与任何二元运算符组合。

$x += 5     # Adds 5 to $x, same as $x = $x + 5 
$x min= 3   # Sets $x to the smaller of $x and 3, same as $x = $x min 3 
$x .= child # Equivalent to $x = $x.child 

[ ] 中包装中缀运算符以创建一个新的化简运算符,该运算符在单个输入列表上工作,从而产生单个值。

say [+] <1 2 3 4 5>;    # OUTPUT: «15␤» 
(((1 + 2) + 3) + 4) + 5 # equivalent expanded version 

« »(或等效的 ASCII)包装一个中缀运算符,以创建一个在两个列表上成对工作的新超运算符。

say <1 2 3> «+» <4 5 6> # OUTPUT: «(5 7 9)␤» 

箭头的方向表示当列表的大小不同时该怎么做。

@a «+« @b # Result is the size of @b, elements from @a will be re-used 
@a »+» @b # Result is the size of @a, elements from @b will be re-used 
@a «+» @b # Result is the size of the biggest input, the smaller one is re-used 
@a »+« @b # Exception if @a and @b are different sizes 

您还可以使用超运算符包装一元运算符。

say -« <1 2 3> # OUTPUT: «(-1 -2 -3)␤»