2009-09-16 16 views
40
def foo 
    f = Proc.new { return "return from foo from inside proc" } 
    f.call # control leaves foo here 
    return "return from foo" 
end 

def bar 
    b = Proc.new { "return from bar from inside proc" } 
    b.call # control leaves bar here 
    return "return from bar" 
end 

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

我認爲return關鍵字在Ruby中是可選的,並且無論您是否要求,您總是return。鑑於此,我發現令人驚訝的是foobar具有不同的輸出,這由fooProc f中包含明確的return這一事實確定。爲什麼明確的回報會影響Proc?

有誰知道這是爲什麼?

回答

63

Ruby有三種構建:

  1. 不是一個對象,並且由{ ... }do ... end創建。
  2. A proc是由Proc.newproc創建的Proc對象。
  3. A lambda是由lambda(或在Ruby 1.8中的proc)創建的Proc

Ruby有三個關鍵字,從返回一些東西:

  1. return終止該方法或lambda它是
  2. next終止塊,PROC,或lambda它是
  3. break終止該屈服於塊或調用的PROC或λ是在該方法中。

在lambdas中,return的行爲類似於next,無論出於何種原因。 nextbreak被命名爲他們,因爲他們是最常見的像each,方法使用的方式,其中終止該塊會導致重複,將恢復與收集的下一個元素,並終止each將導致你休息跳出循環。


如果使用 returnfoo的定義中,您將返回從 foo,哪怕是塊或proc中。要從塊返回,您可以改用 next關鍵字。

def foo 
    f = Proc.new { next "return from foo from inside proc" } 
    f.call # control leaves foo here 
    return "return from foo" 
end 
puts foo # prints "return from foo" 
+0

編輯也提到了lambda的行爲 – sepp2k 2009-09-17 08:49:45

+0

注意,在你的例子中,如果下一個被省略,行爲依然存在。 – 2009-09-17 09:17:44

+1

順便說一句,我認爲我們都做了很好的工作來回答一個不同的問題:)至於爲什麼,我認爲只有馬茨知道,關於閉包的很多東西違反了最少驚喜的原則。 – 2009-09-17 09:33:30

12

這是Proc S上的語義;它不一定是所有塊的語義。我同意這有點令人困惑。這是爲了增加靈活性(也許部分原因是Ruby沒有規範,除了它的實現)。

該行爲在Proc實現中定義。 Lambda的表現方式不同,因此如果您希望return不能退出以外的方法,請使用lambdas。或者,省略Proc中的return關鍵字。

Rubys關閉的深入調查is here。這是一個夢幻般的揭露。

所以:

def foo 
    f = Proc.new { 
    p2 = Proc.new { return "inner proc"}; 
    p2.call 
    return "proc" 
    } 
    f.call 
    return "foo" 
end 

def foo2 
    result = Proc.new{"proc"}.call 
    "foo2 (proc result is: #{result})" 
end 

def bar 
    l = lambda { return "lambda" } 
    result = l.call 
    return "bar (lambda result is: #{result})" 
end 

puts foo 
# inner proc 
puts foo2 
# foo (proc result is: proc) 
puts bar 
# bar (lambda result is: lambda) 
+0

「這是Procs的語義,它不一定是所有塊的語義。」它是由Proc.new創建的Proc實例的語義以及所有「常規」塊(即與「proc」或「lambda」關鍵字一起使用的塊)。 – sepp2k 2009-09-17 08:51:17

+0

的確,我可以添加一個示例,但我認爲我的示例足夠複雜。 – 2009-09-17 09:18:31

+0

出於某種原因,lambda轉換爲塊的行爲就像它們總是塊一樣:'[1] .map&lambda {return「lambda」}'從函數返回。這是JRuby中的錯誤嗎? – 2013-10-20 06:10:34

6

認爲它是這樣的:Proc.new只需創建的代碼塊,調用函數的一部分。 proc/lambda創建一個具有特殊綁定的匿名函數。一些代碼例子可以幫助:

def foo 
    f = Proc.new { return "return from foo from inside Proc.new" } 
    f.call # control leaves foo here 
    return "return from foo" 
end 

相當於

def foo 
    begin 
    return "return from foo from inside begin/end" } 
    end 

    return "return from foo" 
end 

所以很明顯,回報率將剛剛從函數「富」

相比之下

返回:

def foo 
    f = proc { return "return from foo from inside proc" } 
    f.call # control stasy in foo here 
    return "return from foo" 
end 

等同於(忽略綁定,因爲在此示例中未使用):

def unonymous_proc 
    return "return from foo from inside proc" 
end 

def foo 
    unonymous_proc() 
    return "return from foo" 
end 

這顯然不會從foo返回,而是繼續到下一條語句。

+3

儘管這是一個老問題,請注意Ruby 1.8.7和1.9.3之間的區別在後者的Kernel.proc中行爲像Proc.new而不是lambda。 – froginvasion 2013-01-23 22:29:13

相關問題