2012-06-01 16 views
0

請幫我理解爲什麼以下工作。返回一個包裝在lambda中的方法引用

class Dog 
    def bark 
    "woof" 
    end 
end 

bark_string = Dog.new.bark 
puts bark_string     # "woof" - a string at this point 
ref_to_bark = -> { bark_string } # the string a moment ago is now the method again 
ref_to_bark.call     # "woof" 

爲什麼包裹在一個進程/λ的方法的引用返回參照原來的方法?它讓我感到困惑。

回答

3

lambda表達式(和塊,進程)在紅寶石是closures;這意味着在與lambda相同範圍內可用的局部變量可以在內部訪問lambda。例如:

foo = 42 
l = lambda{ p foo } 
l.call() 
#=> 42 

以上應該是沒有什麼比事實,此代碼的工作更令人吃驚:

def make_adder(x) 
    ->(y){ x+y } 
end 
add10 = make_adder(10) 
z = add10.call(32)  #=> 42 

x = 17 
[1,2,3].map do |n| 
    n+x # Whoa, you can use _x_ here?! 
end 
#=> [18,19,20] 

,當你做這樣的事情這是稍微更令人驚訝

同樣,本地變量x(傳遞給方法的參數)由lambda「關閉」,其值保留供參考,只要lambda被調用。

所以,在你的榜樣拉姆達只是「捕獲」的bark_string變量後來就返回它的價值。你的方法從不被第二次調用。


注意,閉包捕獲變量本身,而不僅僅是對象提到了變量:

x = "hello" 
y = x   # reference the same _object_ 
l = ->{ x } # close over the _variable_ itself 
x = "world" # change the variable to point to a new object 

p y,   #=> "hello"  (same object as the original) 
    l[]   #=> "world"  (new object) 
+0

哇,這是我尋找的清晰和徹底的解釋類型。謝謝 – Brand

4

它沒有。 ref_to_bark只是返回bark_string,不調用bark方法。

+0

我看不出你如何能說這是返回'bark_string'。因爲'bark_string'是字符串「woof」。當它用' - > {bark_string}'包裝時,它會再次成爲方法。這是我非常陌生的部分。 – Brand

+1

就像'ref_to_bark = - > {「woof」}',它成爲一種方法,但不是_that_方法。 – Stefan

+0

爲了向你自己證明這個方法沒有被再次調用,試着定義一個像def test這樣的方法;是時候了; end'。你會發現當你用lambda包裝它並調用lambda時,無論等待多久,你仍然會得到與第一次運行該方法相同的時間戳。 – Emily

0

使用 - >定義的lambda稱爲lambda文字。有時叫做stabby lambda。以下內容也會返回相同的結果。

ref_to_bark = lambda { bark_string } 

或者

ref_to_bark = lambda { "woof" }