虽然splat(*
)构造通常被称为splat 运算符,但很明显它与其他一元运算符(如否定)相比是一个不同的野兽({ {1}})运营商。
当在赋值(!
)中使用时,splat在它自己的工作正常(即没有用括号括起来),但在与条件赋值(=
)一起使用时会产生错误。例如:
||=
我不是在寻找做同样事情的替代方法,而是寻找对Ruby内部有更好理解的人来解释为什么splat构造的这种用法在第一种情况下起作用而在第二种情况下不起作用。
答案 0 :(得分:7)
这是我对splat实际目标的理解。这适用于Ruby 2.2 MRI / KRI / YARV。
Ruby splat在赋值期间将对象解构为数组。
当a
为假时,这些示例都提供相同的结果:
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
。这意味着当你展开数组时,没有任何变化。这也意味着如果你愿意,你可以为你自己的任何类定义你自己的解构类型。)
但这些陈述失败了:
*(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))
答案 1 :(得分:0)
通过在表达式中展开java
,您获得*(1..3)
,并且在分配时,它的行为类似于质量赋值,但ruby似乎不支持条件赋值。
即1, 2, 3
只是ruby的语法糖。只需明确使用数组:
a=1,2,3
实际上你只在这里使用部分splat功能 - 它autoconversion to array :)所以你可以这样做:
a ||= [*1..3] #=> [1, 2, 3]