《Programming Ruby》这本书有一个很棒的explanation of blocks and using them。
在 1.9+ 中,传递到块中的参数列表变得更加复杂,允许定义局部变量:
do |a,b;c,d|
some_stuff
end
;c,d 在块内声明两个新的局部变量,它们不接收来自被调用例程的yield 语句的值。 Ruby 1.9+ 保证,如果变量存在于块之外,它们不会被块内的同名变量踩踏。这是新行为; 1.8 会踩到它们。
def blah
yield 1,2,3,4
end
c = 'foo'
d = 'bar'
blah { |a, *b; c,d|
c = 'hello'
d = 'world'
puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}", "d: #{d}"
}
puts c, d
# >> a: 1
# >> b: 2,3,4
# >> c: hello
# >> d: world
# >> foo
# >> bar
还有“splat”运算符*,它在参数列表中起作用:
do |a,*b|
some_stuff
end
将多个值中的第一个分配给“a”,其余的将被捕获在“b”中,这将被视为一个数组。 * 可以在 a 变量上:
do |*a,b|
some_stuff
end
将捕获除最后一个变量之外的所有传入变量,该变量将传递给b。而且,和前两个类似:
do |a,*b,c|
some_stuff
end
会将第一个值分配给a,将最后一个值分配给c,并将所有/任何中间值分配给b。
我认为这是非常强大和巧妙的。
例如:
def blah
yield 1,2,3,4
end
blah { |a, *b| puts "a: #{a}", "b: #{b.join(',')}" }
# >> a: 1
# >> b: 2,3,4
blah { |*a, b| puts "a: #{a.join(',')}", "b: #{b}" }
# >> a: 1,2,3
# >> b: 4
blah { |a, *b, c| puts "a: #{a}", "b: #{b.join(',')}", "c: #{c}" }
# >> a: 1
# >> b: 2,3
# >> c: 4