【问题标题】:Destructuring assignment in object creation对象创建中的解构赋值
【发布时间】:2021-11-07 20:14:16
【问题描述】:

与我的previous question 一样,我无法判断我是否遇到了错误或对 Raku 语义的理解存在漏洞。上次发现是个bug,但怀疑闪电会两次!

一般来说,我知道我可以将命名参数传递给函数,或者使用看起来很像创建 Pair 的语法(例如 f :a(42))或使用 looks a lot like 展平哈希的语法(例如 f |%h )。 (请参阅文档中的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 属性有效,但我更喜欢@ 的语义)。

【问题讨论】:

    标签: arrays constructor raku destructuring rakudo


    【解决方案1】:

    这种行为是有意的吗?

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

    如果是,为什么?

    直觉是:

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

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

    将其强制转换为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;
    

    【讨论】:

    • 谢谢 - 一个非常有帮助和全面的答案!而且,既然我理解了推理,我同意赋值语义对于对象是默认的)
    猜你喜欢
    • 2017-03-18
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    相关资源
    最近更新 更多