当原始变量具有默认强制转换时,有没有办法访问混合组件?

Is there a way to access mixed-in components when the original variable has a default coercion?

例如,在这种情况下:

my @list = (2,) but "bar";
put @list.Str «2␤»

似乎没有办法访问“栏”组件。我错过了什么吗?例如,Set

也会发生同样的情况
my @list = (2,3) but Set(4,5);
put @list.Set; # OUTPUT: «3 2␤»

赋值是复制操作,所以:

my @a = something;

@a 中创建一个 Array,迭代 something,并将每个元素存储在 @a 中。如果改为使用绑定:

my @list := (2,) but "bar";
put @list.Str;

然后将带有mixin的列表绑定到符号@list,输出为:

bar

TL;DR 我想我现在更接近理解你的意思了。我在这个答案的开头分享了基于这种理解的各种解决方案。 (这个答案的其余部分现在可能大部分都没有实际意义,但我把它留了下来,因为我认为它仍然有一些价值,尤其是那个仍然让我困惑的明显错误。)

我现在认为你想要的一些解决方案

role foo { method Str { 42 } }
...
say @bar.Str; # 42

其中 ... 适当填写,例如:

  • class List2 is List does foo {}
    my @bar is List2;
    

    这是做什么的,什么时候:

    • 创建一个新容器类型 List2 组成 List 角色 foo.

    • 永久将变量@bar“绑定”到新容器类型的新实例。

    • 所有这些都发生在编译时

  • my @bar is List;
    @bar does foo;
    

    这是做什么的,什么时候:

    • 永久 在编译时“绑定”变量 @barList 的新实例.

    • 永久foo混合成相同的List实例在运行-time.

  • my @bar := (1,2) but foo
    

    这是做什么的,什么时候:

    • 在编译时从文字 ((1,2)).

      构造一个新的 List 实例
    • 运行时间构造一个实例,这是一个克隆List 从列表文字构造 foo 角色混合。

    • 暂时“绑定”变量@barnewList / foo 对象 ((1,2) but foo).

我的原回答

您共享的代码及其行为主要是基本的普通行为。 jnthn 的回答解释了这些基本方面。这个答案提供了更多细节,并指出了一个让我感到惊讶并且可能是错误的部分。

Is there a way to access mixed-in components when the original variable has a default coercion?

我想我看到了一些意想不到的事情,这可能就是你所说的。但我不会将其描述为“默认强制”,因为“默认”和“强制”在 Raku 中已经具有特定含义,并且与这些无关。模奇怪的行为,这只是 Raku 的普通语义,用于将复数值分配给复数变量。

For instance, in this case:

my @list = (2,) but "bar";

jnthn 的回答解释了为什么这行不通。简而言之,mixin 在复数值上,而不是在每个 within 复数值上,因此它不会作为赋值的一部分被复制。在您开始之前,您的代码已“损坏”。

可以合理地编写这样的东西并期望它能工作:

my @list = (2,) Zbut "bar";
put @list.Str; # «bar␤»

第一行中的Z使用zipbut分布在复数List值中的单数元素上but ] 语义。只有一个元素 -- 2 -- 但如果有更多元素,它也有效:

my @list = 2,3 Zbut "bar", "foo";
put @list.Str; # «bar foo␤»

清楚第二行中发生的事情很有用。

正在对 复数 值调用 .Str 方法(隐式创建并绑定到 @list 作为一部分的 Array声明 my @list).

与大多数编程语言一样,Raku 中的每个例程都主要根据其参数来决定要做什么。和大多数带有方法的 PL 一样,方法可能会根据它们的调用者做不同的事情。

在 Raku 中 .Str 方法,当使用 plural value/variable 调用 distributes a .Str 该复数调用者中的每个元素。 (如果它的任何元素本身是另一个复数,调用将递归地对其元素执行相同的操作。)完成所有操作后,生成的单个字符串系列将在每个字符串之间连接 space。

Same will happen, for instance, with Set

和以前一样,您将再次需要将 mixin 分发到第一行中的各个元素,以便有机会解决问题:

my @list = (2,3) Zbut Set(4,5);

但现在 second 行仍然无法满足您的预期:

put @list.Set; # OUTPUT: «3 2␤»

问题是这次你要处理 .Set

对复数调用 .Set 不同于对复数调用 .Str。它具有完全不同的语义。它所做的是从复数值的元素集合构造一个集合。因此:

say (1,2,3).Set; # Set(1 2 3)

希望到目前为止这一切都有意义。

这里是让我感到惊讶的地方。这似乎有效:

my @list = 2 but Set(4,5);
put @list[0].^name;       # OUTPUT: «Int+{<anon|1>}␤»
put @list[0].Set;         # OUTPUT: «4 5␤»
put @list[0].Set.^name;   # OUTPUT: «Set␤»

但是如果我们更改第一行,事情就不会像我预期的那样工作了:

my @list = (2,3) Zbut Set(4,5);
put @list[0].^name;       # OUTPUT: «Int+{<anon|1>}␤»
put @list[0].Set;         # OUTPUT: «2␤»
put @list[0].Set.^name;   # OUTPUT: «Set␤»

这让我很困惑。我会睡在上面。但现在看来这可能是一个错误。