上下文和上下文化

在许多情况下,需要上下文来解释容器的值。在 Raku 中,我们将使用 context 将容器的值强制转换为某种类型或类,或者决定如何处理它,就像接收器(sink)上下文的情况一样。

Sink 上下文

Sink 相当于 void 上下文,也就是说,我们抛出(在接收器下面)操作的结果或块的返回值的上下文。通常,当语句不知道如何处理该值时,将在警告和错误中调用此上下文。

  1. my $sub = -> $a { return $a² };
  2. $sub; # OUTPUT: «WARNINGS:
  3. Useless use of $sub in sink context (line 1

您可以使用 sink-all 方法在 Iterator 上强制使用该接收器上下文。Proc也可以通过 sink 方法沉没,迫使它们引发异常而不返回任何东西。

通常,如果在 sink 上下文中进行计算,则块将发出警告; 但是,在 sink 上下文中 gather/take 块是显式计算的,并使用 take 显式返回值。

在 sink 上下文中,对象将调用其 sink 方法(如果存在):

  1. sub foo {
  2. return [<a b c>] does role {
  3. method sink { say "sink called" }
  4. }
  5. }
  6. foo
  7. # OUTPUT: sink called

Number 上下文

这个上下文,可能除了上面的所有内容之外,都是*转换*或*解释*上下文,因为它们接收无类型或类型化的变量,并将其类型化为执行操作所需的任何内容。在某些情况下,这意味着转换(例如从 StrNumeric); 在其他情况下只是一种解释(IntStr 将被解释为 IntStr)。

每当我们需要对变量应用数值运算时,就会调用*数字上下文*。

  1. my $not-a-string="1 ";
  2. my $neither-a-string="3 ";
  3. say $not-a-string+$neither-a-string; # OUTPUT: «4»

在上面的代码中,只要只有几个数字而没有其他字符,字符串将在数字上下文中解释。但是,它可以具有任意数量的前导或尾随空格。

可以使用算术运算符强制数字上下文,例如 +-。在该上下文中,Numeric 将调用该方法(如果可用),并将返回的值用作对象的数值。

  1. my $t = True;
  2. my $f = False;
  3. say $t+$f; # OUTPUT: «1»
  4. say $t.Numeric; # OUTPUT: «1»
  5. say $f.Numeric; # OUTPUT: «0»
  6. my $list= <a b c>;
  7. say True+$list; # OUTPUT: «4»

在*列表*那样的东西的情况下,数值通常等于 .elems; 在某些情况下,像Thread 一样,它将返回唯一的线程标识符。

String 上下文

在*字符串上下文中*,值可以作为字符串进行操作。例如,此上下文用于强制非字符串值,以便可以将它们打印到标准输出。

  1. put $very-complicated-and-hairy-object; # OUTPUT: something meaningful

或者当智能匹配正则表达式时:

  1. put 333444777 ~~ /(3+)/; # OUTPUT: «「333」 0 => 「333」»

通常,将在变量上调用 Str 例程以将其上下文化; 因为这个方法是从 Mu 继承的,所以它始终存在,但并不总能保证工作。在某些核心类中,它会发出警告。

是(一元)字符串上下文化器。作为运算符,它连接字符串,但作为前缀运算符,它成为字符串上下文运算符。

  1. my @array = [ [1,2,3], [4,5,6]];
  2. say ~@array; # OUTPUT: «1 2 3 4 5 6»

[~](https://docs.raku.org/language/operators#Reduction_operators) 应用于列表时,这也将在 [reduction] 上下文中发生:

  1. say [~] [ 3, 5+6i, Set(<a b c>), [1,2,3] ]; # OUTPUT: «35+6ic a b1 2 3»

在那个情况下, 空列表或其它容器会字符串化为一个空字符串:

  1. say [~] [] ; # OUTPUT: «
  2. »

由于 ~ 也作为缓冲区连接运算符,因此必须检查每个元素是否为空,因为字符串上下文中的单个空缓冲区将表现为字符串,从而产生错误。

  1. say [~] Buf.new(0x3,0x33), Buf.new(0x2,0x22);
  2. # OUTPUT: «Buf:0x<03 33 02 22>»

然而,

  1. my $non-empty = Buf.new(0x3, 0x33);
  2. my $empty = [];
  3. my $non-empty-also = Buf.new(0x2,0x22);
  4. say [~] $non-empty, $empty, $non-empty-also;
  5. # OUTPUT: «Cannot use a Buf as a string, but you called the Stringy method on it

由于 ~ 将字符串上下文放入此列表的第二个元素,~ 将使用适用于字符串的第二个形式,从而产生所显示的错误。只需确保连接的所有内容都是缓冲区即可避免此问题。

  1. my $non-empty = Buf.new(0x3, 0x33);
  2. my $empty = Buf.new();
  3. my $non-empty-also = Buf.new(0x2,0x22);
  4. say [~] $non-empty, $empty, $non-empty-also; # OUTPUT: «Buf:0x<03 33 02 22>»

通常,上下文会通过调用 contextualizer 将变量强制转换为特定类型; 在 mixins 的情况下,如果混合了上下文类,它将以这种方式运行。

  1. my $described-number = 1i but 'Unity in complex plane';
  2. put $described-number; # OUTPUT: «Unity in complex plane»

but 创建一个 mixin,它使用 Str 方法赋予复数。put 将它 Str 上下文化为一个字符串,即它调用字符串上下文,使用上面显示的结果。