对象创建中的解构赋值

cod*_*ons 9 arrays constructor destructuring rakudo raku

与我之前的问题一样,在这个领域我无法判断我对 Raku 语义的理解是否遇到了错误或漏洞。上次竟然是bug,不过怀疑闪电会劈两次!

\n

一般来说,我知道我可以使用看起来很像创建 Pair 的语法(例如f :a(42))或使用看起来很像展平哈希的语法(例如f |%h)将命名参数传递给函数。(请参阅文档中的参数解构)。通常,这两者是等效的,即使对于非标量参数也是如此:

\n
sub f(:@a) { dd @a }\nmy %h = a => [4, 2];\nf :a([4,2]);  # OUTPUT: \xc2\xabArray element = [4, 2]\xc2\xbb\nf |%h;        # OUTPUT: \xc2\xabArray element = [4, 2]\xc2\xbb\n
Run Code Online (Sandbox Code Playgroud)\n

然而,当使用默认构造函数构造对象时.new,这两种形式似乎给出了不同的结果:

\n
class C { has @.a; }\nmy %h = a => [4, 2];\nC.new: :a([4,2];  # OUTPUT: \xc2\xabC.new(a => ([[4, 2]])\xc2\xbb\nC.new: |%h;       # OUTPUT: \xc2\xabC.new(a => [[4, 2],])\xc2\xbb\n
Run Code Online (Sandbox Code Playgroud)\n

也就是说,传递:a([4,2])结果为二元素数组,但使用参数扁平化语法会生成包含二元素数组的单元素数组。

\n

这种行为是故意的吗?如果是这样,为什么?是否有语法可以用来传入并获取绑定到-sigiled 属性的|%h二元素数组?@(我知道使用$-sigiled 属性有效,但我更喜欢 的语义@)。

\n

Jon*_*ton 11

这种行为是故意的吗?

是的。参数绑定使用绑定语义,而属性初始化使用赋值语义。对数组的赋值遵循Scalar容器,a 的值Hash也是Scalar容器。

如果是这样,为什么?

直觉是:

  • 当调用一个函数时,在它返回之前我们不会做任何事情,因此我们可以有效地借出我们在它执行时传递给它的相同对象。因此,绑定是一种合理的默认设置(但是,可以使用is copy参数来获取赋值语义)。
  • 当创建一个新对象时,它很可能会在构造函数调用之后继续存在。因此,复制(即赋值)语义是一个合理的默认值。

是否有语法可以用来传递 |%h 并获取绑定到 @-sigiled 属性的二元素数组?

将其强制转换为Map

class C { has @.a; }
my %h = a => [4, 2];
say C.new: |%h.Map;
Run Code Online (Sandbox Code Playgroud)

Map或者首先从 a 开始:

class C { has @.a; }
my %h is Map = a => [4, 2];
say C.new: |%h;
Run Code Online (Sandbox Code Playgroud)

  • 谢谢——非常有帮助和全面的答案!而且,既然我理解了推理,我同意赋值语义对于对象来说是默认有意义的) (3认同)