对象创建中的解构赋值
Destructuring assignment in object creation
与我的 一样,这是一个我无法判断我在理解 Raku 语义时是否遇到错误或漏洞的领域。上次结果是bug,怀疑闪电会打两下!
一般来说,我知道我可以将命名参数传递给一个函数,或者使用看起来很像创建 Pair 的语法(例如 f :a(42)
),或者使用文档中 looks a lot like flattening a Hash (e.g., f |%h
). (see argument destructuring 的语法).通常,这两个是等效的,即使对于非标量参数也是如此:
sub f(:@a) { dd @a }
my %h = a => [4, 2];
f :a([4,2]); # OUTPUT: «Array element = [4, 2]»
f |%h; # OUTPUT: «Array element = [4, 2]»
然而,当使用默认的 .new
构造函数构造对象时,这两种形式似乎给出了不同的结果:
class C { has @.a; }
my %h = a => [4, 2];
C.new: :a([4,2]; # OUTPUT: «C.new(a => ([[4, 2]])»
C.new: |%h; # OUTPUT: «C.new(a => [[4, 2],])»
也就是说,传递 :a([4,2])
会产生一个双元素数组,但使用参数展平语法会产生一个包含双元素数组的单元素数组。
这种行为是故意的吗?如果是这样,为什么?我是否可以使用语法来传递 |%h
并将双元素数组绑定到 @
-sigiled 属性? (我知道使用 $
-sigiled 属性是可行的,但我更喜欢 @
的语义)。
Is this behavior intended?
是的。参数绑定使用绑定语义,而属性初始化使用赋值语义。对数组的赋值涉及 Scalar
个容器,Hash
的值是 Scalar
个容器。
If so, why?
直觉是:
- 当调用一个函数时,我们不会在它 returns 之前做任何事情,所以我们可以有效地借出我们在它执行时传递给它的相同对象。因此绑定是一个合理的默认值(但是,可以在参数上使用
is copy
来获得赋值语义)。
- 创建新对象时,它很可能会在构造函数调用之后继续存在。因此复制——即赋值——语义是一个合理的默认值。
And is there syntax I can use to pass |%h in and get the two-element Array bound to an @-sigiled attribute?
强制转换为 Map
:
class C { has @.a; }
my %h = a => [4, 2];
say C.new: |%h.Map;
或者首先从 Map
开始:
class C { has @.a; }
my %h is Map = a => [4, 2];
say C.new: |%h;
与我的
一般来说,我知道我可以将命名参数传递给一个函数,或者使用看起来很像创建 Pair 的语法(例如 f :a(42)
),或者使用文档中 looks a lot like flattening a Hash (e.g., f |%h
). (see argument destructuring 的语法).通常,这两个是等效的,即使对于非标量参数也是如此:
sub f(:@a) { dd @a }
my %h = a => [4, 2];
f :a([4,2]); # OUTPUT: «Array element = [4, 2]»
f |%h; # OUTPUT: «Array element = [4, 2]»
然而,当使用默认的 .new
构造函数构造对象时,这两种形式似乎给出了不同的结果:
class C { has @.a; }
my %h = a => [4, 2];
C.new: :a([4,2]; # OUTPUT: «C.new(a => ([[4, 2]])»
C.new: |%h; # OUTPUT: «C.new(a => [[4, 2],])»
也就是说,传递 :a([4,2])
会产生一个双元素数组,但使用参数展平语法会产生一个包含双元素数组的单元素数组。
这种行为是故意的吗?如果是这样,为什么?我是否可以使用语法来传递 |%h
并将双元素数组绑定到 @
-sigiled 属性? (我知道使用 $
-sigiled 属性是可行的,但我更喜欢 @
的语义)。
Is this behavior intended?
是的。参数绑定使用绑定语义,而属性初始化使用赋值语义。对数组的赋值涉及 Scalar
个容器,Hash
的值是 Scalar
个容器。
If so, why?
直觉是:
- 当调用一个函数时,我们不会在它 returns 之前做任何事情,所以我们可以有效地借出我们在它执行时传递给它的相同对象。因此绑定是一个合理的默认值(但是,可以在参数上使用
is copy
来获得赋值语义)。 - 创建新对象时,它很可能会在构造函数调用之后继续存在。因此复制——即赋值——语义是一个合理的默认值。
And is there syntax I can use to pass |%h in and get the two-element Array bound to an @-sigiled attribute?
强制转换为 Map
:
class C { has @.a; }
my %h = a => [4, 2];
say C.new: |%h.Map;
或者首先从 Map
开始:
class C { has @.a; }
my %h is Map = a => [4, 2];
say C.new: |%h;