为什么Ruby splat在条件赋值中不适用于数组强制?

时间:2015-04-25 11:26:07

标签: ruby

虽然splat(*)构造通常被称为splat 运算符,但很明显它与其他一元运算符(如否定)相比是一个不同的野兽({ {1}})运营商。

当在赋值(!)中使用时,splat在它自己的工作正常(即没有用括号括起来),但在与条件赋值(=)一起使用时会产生错误。例如:

||=

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

2 个答案:

答案 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]