2012-06-07 40 views
0

在Eloquent Ruby中有一個我不明白的代碼示例。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|。這是書中的一個錯字,還是我缺少的東西?

我甚至嘗試在這個代碼中輸入並執行它,我發現我可以添加儘可能多的參數,因爲我想和不會有任何錯誤。但是我仍然不明白爲什麼在這個例子中有兩個參數。

回答

6

這是由於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是最好的。

1

在這個例子中看起來沒有用處,但是您可以將任意數量的參數傳遞給塊,並且它們會被忽略。在這種情況下,您也可以不帶參數地調用它。

相關問題