你必须首先了解&
此处使用的运算符。参见示例:
# The & here converts a block argument to a proc
def a(&blk)
end
# The & here converts the proc to a block
a(&Proc.new { true })
在 proc => block 的情况下,它还能够将一些对象变成 proc,例如:
# The symbol :class gets to_proc called here
[1].map(&:class)
Symbol#to_proc
产生相同的功能如下
[1].map(&Proc.new { |x| x.class })
我不确定这方面的官方文档在哪里(欢迎指点),但从测试看来&nil
实际上根本没有将任何块传递给该方法 - 它没有任何效果:
def a
block_given?
end
a {} # => true
a &:puts # => true
a &nil # => false
现在已经解释清楚了,我可以继续说明为什么需要它。
如果你省略括号super
,所有参数都被传递:
class A
def initialize arg
puts arg && block_given?
end
end
class B < A
def initialize arg
super
end
end
B.new(1) {}
# prints "true" - block and arg were both passed to super
如果您不希望这种情况发生,您可以手动将参数传递给super
。这有一个问题,我稍后会讨论:
class A
def initialize arg1, arg2=nil
puts arg1 && !arg2
end
end
class B < A
def initialize arg1, arg2=nil
super arg1
end
end
B.new 1, 2
# prints "true" - arg1 was passed to super but not arg2
问题是,尽管您可以阻止传递位置参数和关键字参数,但这种方法will not防止块被传递:
class A
def initialize arg1
puts arg1 && block_given?
end
end
class B < A
def initialize arg1
super arg1
end
end
B.new(1) { }
# prints "true" - arg and block were both passed
无论出于何种原因,重要的是不要发生这种情况,因此他们使用了一个我以前从未见过但似乎完成了工作的习语:&nil
。它本质上是在说“不传递任何内容作为块”。我想如果你不这样做,那么块就会自动转发。