2013-02-15 24 views
3

我想更好地瞭解Ruby的封鎖和我碰到這個例子的代碼,我不太明白傳來:瞭解Ruby的瓶蓋

def make_counter 
    n = 0 
    return Proc.new { n = n + 1 } 
end 

c = make_counter 
puts c.call # => this outputs 1 
puts c.call # => this outputs 2 

有人可以幫助我瞭解什麼是真正在上面的代碼時發生我打電話c = make_counter?在我看來,這是我的想法:

Ruby調用make_counter方法並返回一個Proc對象,其中與Proc關聯的代碼塊將爲{ n = 1 }。當執行第一個c.call時,Proc對象將執行與其關聯的塊,並返回n = 1。但是,當執行第二個c.call時,Proc對象是否仍然執行與其關聯的塊,該塊仍然是{ n = 1 }?我不明白爲什麼輸出將變成2

也許我不理解這一點在所有,這將是有益的,如果你能提供什麼在Ruby中實際發生的情況作一些澄清。

回答

8

make_counter時被調用的塊不進行評價。當您通過c.call致電Proc時,將對該塊進行評估和運行。因此,每次運行c.call時,都會評估並運行表達式n = n + 1。所述用於PROC結合將導致n變量保持在範圍內,因爲它(本地n變量)PROC閉合外首先聲明。因此,n將在每次迭代中保持遞增。

爲了進一步闡明這一點:

  • 限定一個Proc(或λ)的塊沒有在初始化評價 - 完全按照你看到它內的代碼被凍結。
  • 好,代碼實際上是「評價」,但不改變冷凍代碼的目的。而是檢查當前在Proc代碼塊上下文中使用的任何變量。由於n是一個局部變量(因爲它是之前定義的行),並且它在Proc中使用,所以它在綁定中被捕獲並伴隨該乘法。
  • call方法被調用在PROC,它將其結合已被捕獲的上下文中執行的「凍結」的代碼。使原已被指定爲0 n,遞增到1。當再次呼籲,同樣n將再次遞增到2等等...
+0

「......最早的PROC關閉外部聲明「並不是一個很好的解釋。 Proc閉包外有很多地方不在Proc範圍內。這只是因爲當Proc被創建時'n'在範圍內。 – 2013-02-15 04:40:20

+0

@AndrewMarshall,通過「Proc閉包之外」,我只是意味着解析器第一次出現在範圍內的'n'不在Proc內部。當然,引用必須在範圍爲它被包含在結合 - 我曾以爲這是顯而易見的...... – PinnyM 2013-02-15 04:44:06

+0

很抱歉,如果這可能是乏味的,但讓我嘗試解釋一下你在我說過的話,並請讓我知道這是否正確:根據定義,代碼塊中的變量n綁定到代碼塊外部的n。這意味着當與Proc關聯的代碼塊通過c.call進行評估時,代碼塊將執行n = n + 1(將1分配給n)並返回1.當與Proc關聯的塊被執行時第二次,它會再次執行n = n + 1,但是這次因爲n現在是1,塊將返回2.我是否正確地解釋了它? – wmock 2013-02-15 04:53:08