2011-05-12 104 views
8

注意: mischa的splat on GitHub有很多很酷的互动*的实例。Ruby中的语法[* a..b]是什么意思?

通过google搜索,我发现有一个办法在Ruby中的一个数字范围的迭代(您的经典C风格的for循环)

for (i = first; i <= last; i++) { 
    whatever(i); 
} 

是做这样的事情

[*first..last].each do |i| 
    whatever i 
end 

但是这个[*first..last]语法究竟发生了什么?我打得四处irb,我看到:

ruby-1.9.2-p180 :001 > 0..5 
=> 0..5 
ruby-1.9.2-p180 :002 > [0..5] 
=> [0..5] 
ruby-1.9.2-p180 :003 > [*0..5] 
=> [0, 1, 2, 3, 4, 5] 
ruby-1.9.2-p180 :004 > *0..5 
SyntaxError: (irb):4: syntax error, unexpected tDOT2, expecting tCOLON2 or '[' or '.' 
*0..5 
    ^

一切我在线阅读讨论了一元星号为扩大和折叠传递给方法,可变长度参数有用的参数很有列出

def foo(*bar) 
    bar 
end 

foo 'tater' # => ["tater"] 
foo 'tater', 'tot' # => ["tater", "tot"] 

我明白了,但我不明白它是如何适用于我在上面的块示例中进行的扩展。我知道Ruby方法是迭代数组或集合,而不是使用数组长度并迭代整数索引。然而,在这个例子中,我真的在处理一个整数列表。 :)

+1

我的整个做法可能是错误的。我应该只是做'(first..last)。每个...',但我仍然想知道那里发生了什么。:) – 2011-05-12 17:17:04

+0

也请试试:'x = * 0..5; px'和'a = [1,2,3]; b = [4,5,6]; c = [* a,* b]; pc '(Ruby 1.9+) – Phrogz 2011-05-12 17:26:58

+1

你也可以使用'first.upto(last){| i | ...}'或'first.step(last){| i | ...}(后一种方法允许你以1以外的增量步进) – Phrogz 2011-05-12 17:32:35

回答

12
[*1..10] 

是一回事

(1..10).to_a # call the "to array" method 

您创建的Array类的实例实现了Enumerable,因此您的循环可以工作。在定义to_a方法的类上,可以使用带括号的splat运算符语法。虽然Splat做的不仅仅是打电话给#to_a,它还是值得Google自己搜索的。

现在,在你的情况下,Range类本身是已经Enumerable,所以你可能只是这样做:

(first..last).each do |v| 
    ... 
end 
3

它被称为splat操作符。如果你喜欢一个参数位置或阵列的特定位置中使用它,它会扩展到它的元素:

a = [1] 
[*a, 3] # => [1, 3] 
b = [1, 2] 
[*b, 3] # => [1, 2, 3] 

你不能用它裸露或范围:

*a..3 # => error. 
(*a..3) # => error. 

当你有东西是不是一个数组,它返回本身:

a = 1 
[*a, 3] # => [1, 3] 
3

[first..last]是只含有1范围对象的数组。 [*first..last]是一个包含该范围的元素作为参数列表发送的数组。 *在参数列表的上下文中起作用。