在Eloquent Ruby中有一个我不理解的代码示例。
class Document
attr_accessor :save_listener
# most of the class omitted...
def on_save( &block )
@save_listener = block
end
def save( path )
File.open( path, 'w' ) { |f| f.print( @contents ) }
@save_listener.call( self, path ) if @save_listener
end
end
# usage
my_doc = Document.new( 'block based example', 'russ', '' )
my_doc.on_save do |doc|
puts "Hey, I've been saved!"
end
为什么@save_listener.call( self, path )
需要两个参数?保存的块看起来只有一个参数|doc|
。这是书中的拼写错误还是我在这里缺少什么?
我甚至尝试输入此代码并执行它,我发现我可以添加任意数量的参数,并且不会出现任何错误。但我仍然不明白为什么在这个例子中有两个参数。
答案 0 :(得分:7)
这是由于Proc
和Lambda
之间存在细微差别。当您使用代码块创建新的Proc
时,可以在调用它时传递任意数量的参数。例如:
proc = Proc.new {|a,b| a + b}
proc.arity #=> 2 -- the number of arguments the Proc expects
proc.call(4,8) #=> 12
proc.call(4,8,15,16,23,42) #=> 12
它接受了这些参数,但没有将它们分配给块中的任何变量。
但是,Lambda
关心参数的数量。
proc = lambda {|a,b| a + b}
proc.arity #=> 2
proc.call(4,8) #=> 12
proc.call(4,8,15,16,23,42) #=> ArgumentError: wrong number of arguments (6 for 2)
这是因为Proc.call
分配方法的参数类似于变量的并行赋值。
num1, num2 = 1,2 #=> num1 is 1, num2 is 2
num1, num2 = 1 #=> num1 is 1, num2 is nil
num1, num2 = 1,2,3,4,5 #=> num1 is 1, num2 is 2 and the rest are discarded
但是,Lambda
不能像这样工作。 Lambda
更像是方法调用而不是变量赋值。
因此,如果您担心只允许一定数量的参数,请使用Lambda
。但是,在此示例中,由于您可以添加块的路径,因此最好Proc
。
答案 1 :(得分:1)
在该示例中看起来没用,但是您可以将所需的参数传递给块,它们将被忽略。在这种情况下,您也可以不带参数调用它。