splat 运算符的意外结果

Unexpected result with splat operator

我有一个散列,其值是一个大小为 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 return [1] 而不是 1

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

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

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

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

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

是的,splash 运算符将 "fold" 和 "unfold" 一个数组,但代码中的问题是您对扇形值所做的操作。

考虑此代码:

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

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

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

会如您所愿。

似乎 ruby 只是 "figures" 如果你将一个数组拼成一个变量,你想要的是数组,而不是值。

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

完全相同

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

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

在赋值中使用 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