2011-09-10 92 views
1

我正在閱讀Eloquent Ruby書(迄今爲止令人敬畏的書),並且不理解關於集合,參數和範圍的一節。下面的代碼...具有參數的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|這PARAM。在改變它以消除不必要的複雜性後,這段代碼會是什麼樣子?

還是意味着在於用with_logging('load', nil)創建@doc是什麼仍是可見的?即使是這種情況,我也不確定底部的with_logging方法如何訪問它。

回答

1

@docinstance variable。它是在一個對象的範圍內定義的(在本例中,是類SomeApplication的實例),通常用於存儲「屬於」實例的值。實例變量始終可用於對象的實例方法。除非將它們變爲屬性,否則它們不在對象外部可用。

您的疑惑re:這個例子可能源於迂迴的方式,作者將方法do_something的值傳遞給方法with_logging。當調用with_logging時,它會收到兩個參數,'save'@doc。在with_logging局部變量description設置爲'save',和局部變量the_object設置爲@doc。然後yield與參數the_object一起被調用,它將the_object傳遞給第二次調用with_logging中定義的代碼塊,您可以將其視爲一種匿名函數。但是,當然,正如作者指出的那樣,在第一次調用with_logging時已經設置了@doc,所以不必將它作爲參數傳遞。他可以寫第二個函數調用:

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

和第一次一樣:

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

然後調用yield不帶任何參數,效果是相同的。

0

這是一個實例變量(由@表示),從而可在整個類,在任何方法。

1

塊(和lambda/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