0

在 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|。这是书中的错字还是我在这里遗漏了什么?

我什至尝试输入这段代码并执行它,我发现我可以添加任意数量的参数并且不会出现任何错误。但是我仍然不明白为什么这个例子中有两个参数。

4

2 回答 2

8

这是由于 和 之间的细微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

它正在接受这些参数,但只是不将它们分配给块中的任何变量。

但是,aLambda关心参数的数量。

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因此最好使用 a。

于 2012-06-07T16:47:39.023 回答
1

在该示例中它看起来没用,但是您可以将任意数量的参数传递给块,它们将被忽略。在这种情况下,您也可以不带参数调用它。

于 2012-06-07T15:53:30.207 回答