带参数的Ruby块

时间:2011-09-10 03:31:52

标签: ruby-on-rails ruby

我正在阅读Eloquent Ruby书(到目前为止很棒的书)并且不理解一个讨论集团,参数和范围的部分。这是代码......

class SomeApplication
# Rest of the class omitted...
  def do_something 
    with_logging('load', nil) { @doc = Document.load( 'book' ) }

    # Do something with the document...

    with_logging('save', @doc) { |the_object| the_object.save } 
  end

  def with_logging(description, the_object) 
    begin
      @logger.debug( "Starting #{description}" )
      yield( the_object )
      @logger.debug( "Completed #{description}" ) 
    rescue
      @logger.error( "#{description} failed!!")
      raise 
    end
  end 
end

这本书说代码比它需要的更复杂,因为@doc在代码块中自动可见。因此,没有必要将其作为论据传递下去。

我不明白他在谈论哪个参数,@ doc或|the_object|。在更改它以消除不必要的复杂性后,此代码会是什么样的?

或者是否意味着在with_logging('load', nil)中创建的@doc仍然是可见的?即使是这种情况,我也不确定底部的with_logging方法如何访问它。

3 个答案:

答案 0 :(得分:1)

块(和lambdas / procs)是闭包。这意味着他们可以访问创建它们的环境中的任何变量。@doc是一个实例变量,因此它始终在类的上下文中。 @doc是绑定到the_object的值,这是不必要的。修改后的代码如下:

class SomeApplication
  # Rest of the class omitted...
  def do_something 
    with_logging('load') { @doc = Document.load( 'book' ) }

    # Do something with the document...

    with_logging('save') { @doc.save } 
  end

  def with_logging(description) 
    begin
      @logger.debug( "Starting #{description}" )
      yield
      @logger.debug( "Completed #{description}" ) 
    rescue
      @logger.error( "#{description} failed!!")
      raise 
    end
  end 
end

答案 1 :(得分:1)

@docinstance variable。它在对象的范围内定义(在本例中为类SomeApplication的实例),通常用于存储“属于”实例的值。实例变量始终可用于对象的实例方法。它们在对象外部不可用,除非您将它们变为属性。

您的困惑:该示例可能源于作者将方法do_something中的值传递给方法with_logging的迂回方式。调用with_logging时,会收到两个参数'save'@doc。在with_logging中,局部变量description设置为'save',局部变量the_object设置为@doc。然后使用参数yield调用the_object,这将the_object传递给第二次调用with_logging中定义的代码块,您可以将其视为一种匿名函数。但是,正如作者所指出的那样,@doc已经在with_logging的第一次调用中设置了,因此没有必要将其作为参数传递。他本可以写第二个函数调用:

with_logging('save') { @doc.save }

和第一个:

with_logging('load') { @doc = Document.load('book') }

然后在没有参数的情况下调用yield,效果会相同。

答案 2 :(得分:0)

它是一个实例变量(由@表示)所以在整个类中都可以使用任何方法。