【问题标题】:Unexpected result with splat operatorsplat 运算符的意外结果
【发布时间】:2015-12-11 14:27:37
【问题描述】:

我有一个哈希,它的值是一个大小为1的数组:

hash = {:start => [1]}

我想解压数组,如下所示:

hash.each_pair{ |key, value| hash[key] = value[0] } # => {:start=>1}

我认为下面的*-operator 可以工作,但它没有给出预期的结果:

hash.each_pair{ |key, value| hash[key] = *value } # => {:start=>[1]}

为什么*value 返回[1] 而不是1

【问题讨论】:

    标签: ruby splat


    【解决方案1】:

    因为应用于hash[]= 方法除了键(放在[] 部分内)和一个喷溅/扩展数组(通常是一系列值)之外只接受一个参数(在这种特殊情况下恰好是单个元素)不能被直接接受为 splatted 的参数。所以它毕竟被[]=的参数接受为一个数组。

    换句话说,一个参数([]= 方法)必须是一个对象,但 splatted 元素(如:foo, :bar, :baz)不是一个对象。将它们解释为对象的唯一方法是将它们放回数组中(例如[:foo, :bar, :baz])。

    使用 splat 运算符,您可以这样做:

    hash.each_pair{|key, value| hash.[]= key, *value}
    

    【讨论】:

    • 如果你使用store,即hash.each_pair{|key, values| hash.store(key, *values)},看起来就不那么奇怪了。但是,如果数组不包含元素或包含多个元素,这两种情况都会引发参数错误。
    【解决方案2】:

    sawa 和 Ninigi 已经指出了为什么任务没有按预期工作。这是我的尝试。

    无论您是对变量、常量进行赋值,还是通过赋值运算符隐式调用 Hash#[]= 之类的赋值方法,Ruby 的赋值功能都有效。为了简单起见,我在以下示例中使用了一个变量。

    在赋值中使用 splat 运算符确实解包数组,即

    a = *[1, 2, 3]
    

    被评估为:

    a = 1, 2, 3
    

    但 Ruby 还允许您在赋值期间通过列出多个值来隐式创建数组。因此,上面又等价于:

    a = [1, 2, 3]
    

    这就是*[1] 产生[1] 的原因 - 它已解包,只是为了转换回数组。

    元素可以使用多重赋值分别赋值:

    a, b = [1, 2, 3]
    a #=> 1
    b #=> 2
    

    或者只是:

    a, = [1, 2, 3]
    a #=> 1
    

    您可以在代码中使用它(注意hash[key] 后面的逗号):

    hash = {:start => [1]}
    hash.each_pair { |key, values| hash[key], = values }
    #=> {:start=>1}
    

    但还有另一种更优雅的方法:您可以通过在数组参数周围加上括号来解包数组:

    hash = {:start => [1]}
    hash.each_pair { |key, (value)| hash[key] = value }
    #=> {:start=>1}
    

    括号将分解数组,将第一个数组元素分配给value

    【讨论】:

    • 每当我看到你发布了一个答案,我在阅读之前就知道它会是最好的。
    【解决方案3】:

    因为 Ruby 在这里表现得出乎意料的聪明。

    没错,splash 运算符会“折叠”和“展开”一个数组,但代码中的关键是你对那个扇形值所做的事情。

    将此代码考虑在内:

    array = ['a', 'b']
    some_var = *array
    array # => ['a', 'b']
    

    如您所见,splat 运算符似乎对您的数组没有任何作用,而这个:

    some_var, some_other_var = *array
    some_var # => "a"
    somet_other_var # => "b"
    

    会做你期望它做的事。

    如果您将数组放入单个变量中,Ruby 似乎只是“数字”,您想要的是数组,而不是值。

    编辑:正如sawa 在 cmets 中指出的那样,hash[key] =variable = 不同。 []= 是 Hash 的一个实例方法,它有自己的 C 代码,在某些情况下可能(理论上)导致不同的行为。我不知道任何例子,但这并不意味着没有。 但为了简单起见,我们可以假设常规变量赋值的行为与hash[key] = 完全相同。

    【讨论】:

    • 请注意,Hash#[]= 与变量赋值 = 不同,尽管它们在某些方面相似。
    • @sawa 变量赋值和赋值方法有何不同?
    • @Stefan 我只想提一下它们是不同的东西。一种是内置的,一种是哈希方法。我并不否认它们的语法是相似的。除非这个答案清楚地表明适用于 = 的内容适用于 Hash#[]=,否则它不是一个完整的答案。
    • @Stefan 正如@sawa 所说,它只是不一样的时期。 Hash#[]= 方法的 C 代码比常规赋值更“复杂”,在某些情况下可能会导致不同的行为。我想不出任何例子,但这并不意味着没有:)
    • @Stefan 这并没有改变这两种方法以不同方式处理其参数的事实,与数组相比,这可能导致参数列表的不同行为...... splat 运算符不是是什么改变了它的行为,它是接收评估结果的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 2014-07-01
    • 2012-04-03
    • 2012-04-09
    • 1970-01-01
    相关资源
    最近更新 更多