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

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

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

词法约定

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

也参阅 Unicode versus ASCII symbols.

自由形式

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

所以你可以写

  1. if True {
  2. say "Hello";
  3. }

  1. if True {
  2. say "Hello"; # Bad indentation intended
  3. }

  1. if True { say "Hello" }

或者甚至

  1. if True {say "Hello"}

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

Unspace

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

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

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

用分号分割语句

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

  1. say "Hello";
  2. say "world";

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

  1. say "Hello";
  2. say "world"
  1. if True {
  2. say "Hello"
  3. }
  4. say "world"

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

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

  1. if True { say "Hello" }
  2. say "world";

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

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

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

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

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

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

注释

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

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

单行注释

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

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

多行 / 嵌套注释

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

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

这些注释可以扩展到多行

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

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

Pod 注释

Pod 语法可用于多行注释

  1. say "this is code";
  2. =begin comment
  3. Here are several
  4. lines
  5. of comment
  6. =end comment
  7. say 'code again';

标识符

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

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

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

普通标识符

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

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

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

扩展标识符

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

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

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

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

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

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

  1. # exemplary valid extended identifiers:
  2. postfix:<²> # the official long name of the operator in $x²
  3. WOW:That'sAwesome
  4. WOW:That's<<🆒>>
  5. party:sweet(16)
  6. # exemplary invalid extended identifiers:
  7. party:16<sweet> # 16 is not an ordinary identifier
  8. party:16sweet
  9. party:!a # ...and neither is !a
  10. party:$a # ...nor $a

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

  1. infix:<+>
  2. infix:<<+>>
  3. infix:«+»
  4. infix:['+']
  5. infix:('+')

同样,所有这些都有效:

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

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

  1. my $a:b<c>:d<e> = 100;
  2. my $a:d<e>:b<c> = 200;
  3. say $a:b<c>:d<e>; # OUTPUT: «100
  4. », NOT: «200
  5. »

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

  1. use ThatModule:auth<Somebody>:ver<2.7.18.28.18>
  2. use ThatModule:ver<2.7.18.28.18>:auth<Somebody>

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

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

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

  1. constant $what = 'are';
  2. my @we:<are>= <the champions>;
  3. say @we$what»; # OUTPUT: «[the champions]
  4. »
  5. say @we:<$what>;
  6. # Compilation error: Variable '@we:<$what>' is not declared

组合标识符

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

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

  1. module MyModule { # declare a module package
  2. our $var = "Hello"; # declare package-scoped variable
  3. }
  4. say $MyModule::var # OUTPUT: «Hello
  5. »

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

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

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

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

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

  1. my $buz = "quux";
  2. my $bur::quux = 7;
  3. say $bur::($buz); # OUTPUT: «7
  4. »

项 term:<>

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

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

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

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

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

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

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

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

语句和表达式

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

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

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

是一个错误,

  1. my $x = do if True { 42 };

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

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

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

变量

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

  1. # declaration:
  2. my $number = 21;
  3. # usage:
  4. say $number * 2;

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

裸字 (常量,类型名)

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

  1. say Int; # OUTPUT: «(Int)
  2. »
  3. # ^^^ type name (built in)
  4. constant answer = 42;
  5. say answer;
  6. # ^^^^^^ constant
  7. class Foo {
  8. method type-name {
  9. self.^name;
  10. # ^^^^ built-in term 'self'
  11. }
  12. }
  13. say Foo.type-name; # OUTPUT: «Foo
  14. »
  15. # ^^^ type name

包和限定名

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

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

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

字面量

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

字符串字面量

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

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

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

  1. say "🔔\a"; # OUTPUT: «🔔␇
  2. »

数字字面量

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

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

  1. 1000000
  2. 1_000_000
  3. 10_00000
  4. 100_00_00
Int 字面量

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

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

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

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

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

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

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

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

Pair 字面量

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

Arrow pairs

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

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

没有显式值的简短形式:

  1. my $thing = 42;
  2. :$thing # same as thing => $thing
  3. :thing # same as thing => True
  4. :!thing # same as thing => False

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

  1. :42thing # same as thing => 42
  2. :٤٢thing # same as thing => 42

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

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

thaa 字母在数字之前。

具有显式值的长形式:

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

Boolean 字面量

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

Array 字面量

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

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

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

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

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

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

Hash 字面量

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

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

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

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

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

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

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

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

Regex 字面量

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

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

签名字面量

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

  1. say "match!" if 5, "fish" ~~ :(Int, Str); # OUTPUT: «match!
  2. »
  3. my $sig = :(Int $a, Str);
  4. say "match!" if (5, "fish") ~~ $sig; # OUTPUT: «match!
  5. »
  6. given "foo", 42 {
  7. when :(Str, Str) { "This won't match" }
  8. when :(Str, Int $n where $n > 20) { "This will!" }
  9. }

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

声明

变量声明

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

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

子例程声明

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

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

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

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

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

  1. package P { }
  2. module M { }
  3. class C { }
  4. role R { }
  5. grammar G { }

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

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

多重分派的声明

另请参见多重分派。

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

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

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

  1. multi method greet { }
  2. multi method greet(Str $name) { }

子例程调用

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

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

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

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

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

优先级下降

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

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

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

运算符

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

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

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

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

元运算符

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

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

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

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

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

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

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

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

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

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