2009-09-16 6 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입니다. 그렇다면 foobarfooProc f에 명시적인 return이 포함되어 있다는 사실에 따라 출력이 달라지기 때문에 놀랍습니다.명시 적 리턴이 Proc에서 차이를 만드는 이유는 무엇입니까?

왜 이런 경우인지 알고 계십니까?

답변

63

루비 세 구조 가지고

  1. 블록 개체 아니다 및 {} ... 또는 ... doend에 의해 생성된다.
  2. procProc.new 또는 proc으로 생성되는 Proc 개체입니다.
  3. 람다lambda (또는 Ruby 1.8에서는 proc)으로 생성 된 Proc입니다.

루비 무언가로부터 반환 키워드 3 있습니다.

  1. return 그것이 인 방법 또는 람다 종료를
  2. next
  3. 그것이 인 블록, PROC 또는 람다를 종료
  4. . break은 블록으로 반환되거나 proc 또는 lambda가 호출 된 메소드를 종료합니다.

람다에서 return은 어떤 이유로 든 next처럼 동작합니다. nextbreak 블록을 종료하면 반복이 컬렉션의 다음 요소와 다시 시작하게됩니다들이 가장 일반적으로 each 같은 방법으로 사용되기 때문에 그들이 길을 명명하고 each을 종료하는 것은 휴식 당신의 원인이됩니다 루프 밖으로. 당신이 foo의 정의 내부 return를 사용하는 경우


, 당신은 블록 또는 PROC 내부에있는 경우에도, foo에서 돌아갑니다. 블록에서 돌아 오려면 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

+0

note 다음 예가 생략 된 경우 예에서 동작이 유지됩니다. –

+1

btw, 나는 우리 모두가 다른 질문에 답하는 훌륭한 일을했다고 생각한다. 이유에 관해서, 나는 Matz만이 알고 있다고 생각한다. 클로저 주변의 많은 것들은 최소한의 놀라움의 원칙을 위반한다. –

12

이것은 Proc s에 대한의 L입니다. 모든 블록에 대한 의미론 일 필요는 없습니다. 나는 이것이 약간 혼란 스럽다는 데 동의한다. 유연성이 추가 되었기 때문입니다. (부분적으로 루비는 그 구현을 제외하면 사양이 없습니다).

동작은 Proc 구현에서 정의됩니다. Lambda의 동작이 다르기 때문에 return을 포함하지 않는 방법으로을 종료하지 않으려면 lambdas을 사용하십시오.또는 Proc에서 return 키워드를 생략하십시오.

루비 클로저에 대한 심층적 인 조사 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

+0

사실, 예제를 추가 할 수는 있지만 예제가 충분히 복잡하다고 생각합니다. –

+0

람다가 블록으로 변환 된 이유는 무엇입니까?'[1] .map & lambda {return "lambda"}'는 함수에서 반환됩니다. 이것은 JRuby의 버그입니까? –

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 

에 해당 그래서 반환 단지 기능 'foo는'달리

에서 반환 것이 분명하다 :

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처럼 작동합니다. – froginvasion