尽管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/