上下文和上下文器

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

Sink 上下文

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

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

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

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

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

sub foo {
    return [<a b c>] does role {
        method sink { say "sink called" }
    }
}
foo
# OUTPUT: sink called 

Number 上下文

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

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

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

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

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

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

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

String 上下文

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

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

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

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

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

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

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

[~] 应用于列表时,这也将在 reduction 上下文中发生:

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

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

say [~] [] ; # OUTPUT: «␤» 

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

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

然而,

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

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

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

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

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

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