Raku 中的 *, $_ 和 $

cale2 问了一个很难的问题

今天卡尔2拒绝问简单的问题。我们来看它今天问了什么难题:

我需要一份关于 * vs $_ vs $ 的指南。

这个问题问得多么好。那三种东西都是语法糖, 因为上下文转换, 它们能很好地避免折行和更少的 bugs。

我们从我们的老朋友主题变量 $_ 开始。在 Perl 5 中它刚好出现在每个 sub 的外面。在 Raku 中它出现在块的默认值之外。

my &block =  { 'oi?' };
&block.signature.say;
# OUTPUT?(;; $_? is raw)??

块的默认签名是一个名为 $_ 的位置参数。因此每个块都有一个主题变量 $_。还有其他设置 $_ 主题变量的语句,而不引入一个新的块,像 withgivengiven 的确引入了一个块,但它是特殊的,我在这里不说明细节)。

say $_ with 42;
# OUTPUT ?42??

因为它是默认的, Raku 会在很多地方期待它的出现。最突出的是当没有对象方法调用时。

$_ = 42; say 'oi?' when 42;
.say;
# OUTPUT?oi??42??

一个单独的 $ 实际上是两个(有一点)的东西。在签名中,它是一个我们永远不能使用的位置参数标记(也许是因为我们不在乎),因为它没有名字,因此在它所应用的例程中不引入符号。它对于 protos 和免费的浮点签名很有用。它的第二个用途实际上引入了一个容器,也没有符号。它也是一个状态变量,它的初始化器(如果有一个)不被处理为状态,并将被调用多于一次。我们可以使用匿名状态变量来计数东西。

my @a = <a b c d>;
for @a { say @a[$++] };

# OUTPUT?a?b?c?d??

我们可以滥用匿名变量 $ 在列表赋值中跳过我们不想要的值。当我们从一个子例程中得到一个短的列表时会很简洁。

my ($,$,$c) = <a b c d>;
say $c;
# OUTPUT?c??

我很享受这样的事实,我懒得给一次性变量起名字。认知负荷越小越好。

Whatever * 是问题的难点。有时它是一个语法糖标记,我们用它来告诉 Raku 我们不关心什么将被选中。在其他时候,它意味着 Inf, 意思是它们中的所有。

my @a = <a b c d>;
put @a.pick(*);

# OUTPUT?c d b a??

如果在参数列表中使用一个单独的 *,它将变成单例 Whatever。由于我们可以要求签名中的值,我们可以为 muitis 提供接口。

multi sub foo(Int $i){ $i * 42 };
multi sub foo(Whatever){ <42 oi? ?>.pick };
say foo(*);
# OUTPUT???? (your results may vary)

如果我们在包含运算符或调用的语句中使用 *,它会形成一个没有作用域的块,并像一个占位符变量一样运行,而不会丢失该块由 * 生成的信息。生成的 Callable 的类型是 Wh??ateverCode 并且当提供了 Sub 或方法时, 例程可以在它上面采取不同的行动。与真正的占位符变量相反, Whatever 可以用在 where 子句中。

sub foo($a where * < 10){}

对于他的问题, 这不是一个完整的答案。这就是为什么我建议卡尔2去阅读文档。

comments powered by Disqus