尽管splat(*)构造通常被称为splat运算符,但与其他一元运算符(例如negation(!)运算符)相比,它显然是不同的野兽。

当在赋值(=)中使用时,splat本身可以很好地工作(即不放在括号中),但在条件赋值(||=)中使用时,会产生错误。例子:

a = *(1..3)
#=> [1, 2, 3]

b ||= *(1..3)
SyntaxError: (irb):65: syntax error, unexpected *

我不是在寻找做同一件事的替代方法,而是在寻找对Ruby内部有更好了解的人来解释为什么splat构造的这种用法在第一种情况下有效,而在第二种情况下无效。

最佳答案

这是我对splat的实际目标的理解。这是针对Ruby 2.2 MRI/KRI/YARV的。

Ruby splat在分配过程中将对象分解为数组。

a为falsey时,这些示例都提供相同的结果:

a = *(1..3)
a = * (1..3)
a =* (1..3)
a = *1..3
a = * 1..3
a = * a || (1..3)
a = * [1, 2, 3]
=> [1, 2, 3]

splat会在分配期间进行销毁,就像您编写此代码一样:
a = [1, 2, 3]

(注意:splat调用#to_a。这意味着当您对数组进行splat时,没有任何变化。这也意味着您可以根据需要为自己的任何类定义自己的解构类型。)

但是这些语句失败了:
*(1..3)
* 1..3
* [1,2,3]
false || *(1..3)
x = x ? x : *(1..3)
=> SyntaxError

这些语句失败是因为在发生splat时没有确切的赋值发生。

您的问题是这种特殊情况:
b ||= *(1..3)

Ruby将其扩展为:
b = b || *(1..3)

该语句失败,因为在发生splat时没有确切的分配发生。

如果需要在自己的代码中解决此问题,则可以使用temp var,例如:
b ||= (x=*(1..3))

值得一提的是:位于表达式左侧的splat有完全不同的用法。在并行分配期间,此splat是低优先级的贪婪收集器。

例子:
*a, b = [1, 2, 3]  #=> a is [1, 2], b is 3
a, *b = [1, 2, 3]  #=> a is 1, b is [2, 3]

所以这确实解析:
*a = (1..3)  #=> a is (1..3)

它将a设置为右侧的所有结果,即范围。

在极少数情况下,可以将splat理解为解构器或收集器,那么解构器具有优势。

这行:
x = * y = (1..3)

对此进行评估:
x = *(y = (1..3))

不是这个:
x = (*y = (1..3))

关于ruby - 为什么Ruby splat无法在条件赋值中用于数组强制?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29864514/

10-13 02:10