【问题标题】:Eloquent Ruby - saving code blocks to execute later exampleEloquent Ruby - 保存代码块以执行后面的示例
【发布时间】:2012-06-07 15:48:56
【问题描述】:

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

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

【问题讨论】:

    标签: ruby block


    【解决方案1】:

    这是由于ProcLambda 之间的细微差别。当您使用代码块创建新的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

    【讨论】:

      【解决方案2】:

      在那个例子中它看起来没什么用,但是你可以向块传递任意数量的参数,它们会被忽略。在这种情况下,您也可以不带参数调用它。

      【讨论】:

        猜你喜欢
        • 2021-07-15
        • 1970-01-01
        • 2016-11-15
        • 1970-01-01
        • 1970-01-01
        • 2012-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多