Raku 中的 proto 关键字

The proto keyword in Raku

今天,我们正在关注 proto 关键字。它向编译器提供了关于你打算创建 multi-subs 的提示。

例子 1

考虑一个翻转字符串或使整数变成负数的函数示例。

multi sub f(Int $x) {
    return -$x;
}

multi sub f(Str $x) {
    return $x.flip;
}

say f(42);      # -42
say f('Hello'); # olleH

如果我们创建另一个接收两个参数的函数的变体,会怎么样?

multi sub f($a, $b) {
    return $a + $b;
}

say f(1, 2); # 3

这个代码完美的工作,但它看起来像它的和谐是破碎的。即使函数的名称没有提及它的作用,我们也打算设置一个函数,以某种方式返回它的参数的“反射”版本。将两个数字相加的函数不适合这个想法。

所以,现在是在 proto 关键字的帮助下清楚地宣布意图的时候了。

proto sub f($x) {*}

现在,尝试调用双参数函数将无法编译:

===SORRY!=== Error while compiling proto.pl
Calling f(Int, Int) will never work with proto signature ($x)
at proto.pl:15
------> say ⏏f(1,2)

单参变量的调用完美地工作。原型定义为函数f创建了一个模式:它的名字是f,并且它需要一个标量参数。多功能指定行为并将其专业知识缩小到整数或字符串。

例子 2

另一个例子涉及函数签名中带有两个类型参数的原型定义。

proto sub g(Int $x, Int $y) {*}

在这个例子中,该函数返回两个整数的和。当其中一个数字比另一个数字大得多时,较小的数字被忽略为不够重要:

multi sub g(Int $x, Int $y) {
   return $x + $y;
}

multi sub g(Int $x, Int $y where {$y > 1_000_000 * $x}) {
   return $y;
}

使用整数参数调用该函数并查看 Raku 如何选择正确的变体:

say g(1, 2);          # 3
say g(3, 10_000_000); # 10000000

难道你忘记两个整数上持有的原型了吗?试一试传递浮点数字:

say g(pi, e);

我们得到一个编译时错误:

===SORRY!=== Error while compiling proto-int.pl
Calling g(Num, Num) will never work with proto signature (Int $x, Int $y)
at proto-int.pl:13
------> say ⏏g(pi, e);

该原型已经捕捉到函数用法中的错误。如果 g sub 没有 proto 会发生什么?该函数仍未调用,但错误消息不同。这次它发生在运行时:

Cannot resolve caller g(3.14159265358979e0, 2.71828182845905e0); none of these signatures match:
 (Int $x, Int $y)
 (Int $x, Int $y where { ... })
 in block <unit> at proto-int.pl line 13

对于浮点数我们仍然没有可接受的签名,但编译器在程序流到达代码之前无法看到它。

Raku 

comments powered by Disqus