Ruby 1.8에서는 proc / lambda와 다른 한편에 미묘한 차이가 Proc.new
있습니다.
- 그 차이점은 무엇입니까?
- 어느 것을 선택할지 결정하는 방법에 대한 지침을 줄 수 있습니까?
- Ruby 1.9에서는 proc과 lambda가 다릅니다. 거래는 무엇입니까?
Ruby 1.8에서는 proc / lambda와 다른 한편에 미묘한 차이가 Proc.new
있습니다.
답변:
로 만든 발동 사이의 또 다른 중요하지만 미묘한 차이 lambda
로 작성 발동은 Proc.new
그들이 처리하는 방법입니다 return
문 :
lambda
proc에서 return
명령문은 proc 자체에서만 리턴합니다.Proc.new
-created 시저의 return
문은 조금 더 놀라운 일이다 : 그것은 단지 PROC에서하지 제어를 반환 뿐만 아니라 시저를 둘러싸는 방법에서!여기에 lambda
proc이 생성 return
되었습니다. 그것은 당신이 아마 기대하는 방식으로 행동합니다 :
def whowouldwin
mylambda = lambda {return "Freddy"}
mylambda.call
# mylambda gets called and returns "Freddy", and execution
# continues on the next line
return "Jason"
end
whowouldwin
#=> "Jason"
이제 여기에 Proc.new
생성 된 proc의 return
동일한 작업이 있습니다. 루비가 가장 자랑스런 서프라이즈 원칙을 위반 한 사례 중 하나를 보려고합니다.
def whowouldwin2
myproc = Proc.new {return "Freddy"}
myproc.call
# myproc gets called and returns "Freddy",
# but also returns control from whowhouldwin2!
# The line below *never* gets executed.
return "Jason"
end
whowouldwin2
#=> "Freddy"
이 놀라운 행동 (타이핑이 적음) 덕분에 나는 procs를 만들 때 lambda
over를 사용하는 것을 선호 Proc.new
합니다.
proc
방법도 있습니다. 단지 속기 Proc.new
입니까?
proc
동일합니다Proc.new
proc
동작 합니다. 그것은 루비 문서가 부정확하다는 것을 의미합니다. lambda
Proc.new
proc
같은 역할을 lambda
1.8에서,하지만 같은 역할 Proc.new
1.9 인치 Peter Wagenet의 답변을 참조하십시오.
lambda
는 익명의 방법입니다. 그것은 메소드이기 때문에 값을 반환하고 그것을 호출 한 메소드는 무시하고 다른 값을 반환하는 것을 포함하여 원하는 모든 것을 할 수 있습니다. A Proc
는 코드 스 니펫에 붙여 넣는 것과 같습니다. 방법처럼 작동하지 않습니다. 따라서에서 반환이 발생 Proc
하면 호출 한 메서드 코드의 일부일뿐입니다.
추가 설명을 제공하려면 다음을 수행하십시오.
Joey는의 복귀 행동 Proc.new
이 놀랍다 고 말합니다 . 그러나 Proc.new가 블록처럼 동작한다고 생각할 때 이것이 블록이 동작하는 방식과 마찬가지로 놀라운 것은 아닙니다. 반면에 lambas는 메소드와 비슷하게 동작합니다.
이것은 실제로 procs가 arity (논쟁 수)에 관해서 융통성이있는 이유를 설명하지만 람다는 그렇지 않습니다. 블록은 모든 인수를 제공 할 필요는 없지만 메소드가 제공합니다 (기본값이 제공되지 않는 한). 람다 인수 기본값을 제공하는 것은 Ruby 1.8에서 옵션이 아니지만, 이제 Ruby 1.9에서 대체 람다 구문을 사용하여 지원됩니다 (webmat에서 알 수 있음).
concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1) # => "12"
그리고 Michiel de Mare (OP)는 Ruby 1.9에서 Arity와 동일하게 동작하는 Procs와 lambda에 대해 올바르지 않습니다. 위와 같이 여전히 1.8에서 동작을 유지한다는 것을 확인했습니다.
break
진술은 실제로 Procs 또는 람다에서별로 의미가 없습니다. Procs에서는 휴식이 이미 완료된 Proc.new에서 돌아옵니다. 람다가 본질적으로 방법이기 때문에 람다에서 벗어나는 것은 의미가 없으며, 최상위 수준의 방법에서 결코 벗어나지 않을 것입니다.
next
, redo
및 raise
Procs와 lambdas에서 동일하게 작동합니다. 반면 retry
어느 쪽도 허용되지 않으며 예외가 발생합니다.
마지막으로이 proc
방법은 일관성이없고 예상치 못한 동작이 있으므로 사용해서는 안됩니다. Ruby 1.8에서는 실제로 람다를 반환합니다! Ruby 1.9에서는이 문제가 해결되었으며 Proc을 반환합니다. Proc을 만들려면을 사용하십시오 Proc.new
.
자세한 내용 은이 정보의 대부분을 제공하는 O'Reilly의 The Ruby Programming Language 를 적극 권장 합니다.
break
프로세서 수의 인상에서 LocalJumpError
, 반면 break
람다의 동작합니다에서 불과 같은 return
( 즉 , return nil
).
차이점 과 차이점을 보여주는 이 페이지 를 찾았습니다 . 페이지에 따르면 유일한 차이점은 람다는 허용되는 인수 수에 대해 엄격한 반면 누락 된 인수는로 변환한다는 것 입니다. 차이점을 설명하는 IRB 세션의 예는 다음과 같습니다.Proc.new
lambda
Proc.new
nil
irb (main) : 001 : 0> l = 람다 {| x, y | x + y} => # <Proc : 0x00007fc605ec0748 @ (irb) : 1> irb (main) : 002 : 0> p = Proc.new {| x, y | x + y} => # <Proc : 0x00007fc605ea8698 @ (irb) : 2> irb (main) : 003 : 0> l.call "hello", "world" => "helloworld" irb (main) : 004 : 0> p.call "hello", "world" => "helloworld" irb (main) : 005 : 0> l. "hello"전화 ArgumentError : 잘못된 개수의 인수 (1/2) 부터 (irb) : 1 (irb) : 5 :`call '에서 에서 (irb) : 5 : 0에서 irb (main) : 006 : 0> p.call "hello" TypeError : nil을 문자열로 변환 할 수 없습니다 from (irb) : 2 : in`+ '에서 에서 (irb) : 2 (irb) : 6 :`call '에서 에서 (irb) : 6 : 0에서
오류 허용 동작을 구체적으로 원하지 않는 한이 페이지에서는 람다 사용을 권장합니다. 이 정서에 동의합니다. 람다를 사용하는 것은 조금 더 간결한 것처럼 보이며, 그와 같은 의미없는 차이로 인해 평균 상황에서 더 나은 선택 인 것 같습니다.
루비 1.9에 관해서는, 미안하지만, 아직 1.9를 보지 않았지만 그들이 그렇게 많이 바꿀 것이라고는 생각하지 않습니다 (그러나 내 말을하지 마십시오. 나는 아마도 틀렸다.)
미묘한 차이점에 대해서는 많이 말할 수 없습니다. 그러나 Ruby 1.9는 이제 람다 및 블록에 대한 선택적 매개 변수를 허용합니다.
1.9 이하의 스테이 비 람다에 대한 새로운 구문은 다음과 같습니다.
stabby = ->(msg='inside the stabby lambda') { puts msg }
루비 1.8에는 그런 문법이 없었습니다. 블록 / 람다를 선언하는 기존의 방법은 선택적 인수를 지원하지 않았습니다.
# under 1.8
l = lambda { |msg = 'inside the stabby lambda'| puts msg }
SyntaxError: compile error
(irb):1: syntax error, unexpected '=', expecting tCOLON2 or '[' or '.'
l = lambda { |msg = 'inside the stabby lambda'| puts msg }
그러나 Ruby 1.9는 이전 구문에서도 선택적 인수를 지원합니다.
l = lambda { |msg = 'inside the regular lambda'| puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez
Leopard 또는 Linux 용 Ruby1.9를 빌드하려면 이 기사 (shameless self promotion)를 확인하십시오.
짧은 대답 : 중요한 것은 무엇입니까? return
람다는 자체를 반환하고 proc은 자체를 반환하고 함수를 호출합니다.
덜 명확한 것은 각각을 사용하려는 이유입니다. 람다는 기능적 프로그래밍 의미에서해야 할 일입니다. 기본적으로 현재 범위가 자동으로 바인딩되는 익명의 방법입니다. 둘 중 람다는 아마도 사용해야 할 것입니다.
반면 Proc는 언어 자체를 구현하는 데 실제로 유용합니다. 예를 들어 "if"문 또는 "for"루프를 구현할 수 있습니다. proc에서 발견 된 모든 리턴은 단지 "if"문이 아니라 호출 한 메소드에서 리턴됩니다. 이것은 언어가 작동하는 방식, "if"문이 작동하는 방식입니다. 그래서 루비는 이것을 커버 아래에서 사용하고 강력 해 보였기 때문에 그냥 노출했습니다.
루프, if-else 구문 등과 같은 새로운 언어 구문을 생성하는 경우에만 필요합니다.
나는 queston의 세 번째 방법 인 "proc"에 대해 아무런 언급도하지 않았지만 더 이상 사용되지 않지만 1.8과 1.9에서 다르게 처리되었습니다.
다음은 세 가지 유사한 호출의 차이점을 쉽게 확인할 수있는 상당히 자세한 예입니다.
def meth1
puts "method start"
pr = lambda { return }
pr.call
puts "method end"
end
def meth2
puts "method start"
pr = Proc.new { return }
pr.call
puts "method end"
end
def meth3
puts "method start"
pr = proc { return }
pr.call
puts "method end"
end
puts "Using lambda"
meth1
puts "--------"
puts "using Proc.new"
meth2
puts "--------"
puts "using proc"
meth3
proc
1.8에서 람다를 반환했습니다. 1.9에서 proc을 반환하도록 수정되었습니다. 그러나 이것은 중대한 변화입니다. 따라서 더 이상 사용하지 않는 것이 좋습니다
Ruby의 Closures는 Ruby 와 함께 Ruby에서 블록, 람다 및 프로세스가 작동하는 방법에 대한 훌륭한 개요입니다.
람다는 다른 언어와 마찬가지로 예상대로 작동합니다.
유선 Proc.new
은 놀랍고 혼란 스럽다.
에 return
의해 생성 된 proc 의 문장 Proc.new
은 그 자체뿐만 아니라 그것을 둘러싸는 메소드에서도 제어를 반환 합니다 .
def some_method
myproc = Proc.new {return "End."}
myproc.call
# Any code below will not get executed!
# ...
end
Proc.new
블록과 마찬가지로 코드를 둘러싸는 메서드에 삽입 한다고 주장 할 수 있습니다 . 그러나 Proc.new
블록은 개체의 일부인 반면 개체를 만듭니다 .
그리고 lambda와와의 또 다른 차이점 Proc.new
은 (잘못된) 인수를 처리하는 것입니다. 람다는 그것에 대해 불평하면서 Proc.new
추가 인수 를 무시하거나 인수가 없음을 nil로 간주합니다.
irb(main):021:0> l = -> (x) { x.to_s }
=> #<Proc:0x8b63750@(irb):21 (lambda)>
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #<Proc:0x8b59494@(irb):22>
irb(main):025:0> l.call
ArgumentError: wrong number of arguments (0 for 1)
from (irb):21:in `block in irb_binding'
from (irb):25:in `call'
from (irb):25
from /usr/bin/irb:11:in `<main>'
irb(main):026:0> p.call
=> ""
irb(main):049:0> l.call 1, 2
ArgumentError: wrong number of arguments (2 for 1)
from (irb):47:in `block in irb_binding'
from (irb):49:in `call'
from (irb):49
from /usr/bin/irb:11:in `<main>'
irb(main):050:0> p.call 1, 2
=> "1"
proc
Ruby 1.8에서 BTW 는 람다를 생성하는 반면 Ruby 1.9+에서는처럼 Proc.new
혼동되어 실제로 혼동됩니다.
나는 이것에 대해 조금 늦었지만 Proc.new
주석에 언급되지 않은 것에 대해 하나의 위대한 것이 거의 알려지지 않은 것이 있습니다. 에 의해으로 문서 :
Proc::new
첨부 된 블록이있는 메소드 내에서만 블록없이 호출 될 수 있으며,이 경우 해당 블록은Proc
객체 로 변환됩니다 .
즉, Proc.new
항복 방법을 체인으로 묶을 수 있습니다.
def m1
yield 'Finally!' if block_given?
end
def m2
m1 &Proc.new
end
m2 { |e| puts e }
#⇒ Finally!
&block
인수 를 선언하는 것과 같은 일을 def
하지만 def arg 목록에서 인수 를 선언 하지 않아도됩니다.
강조 그것의 가치가 그 return
어휘 둘러싸는 방법에서 PROC 반환, 즉에서 proc 디렉토리가 생성 된 방법 , 하지 proc 디렉토리를 호출하는 방법. 이것은 procs의 클로저 속성의 결과입니다. 따라서 다음 코드는 아무것도 출력하지 않습니다.
def foo
proc = Proc.new{return}
foobar(proc)
puts 'foo'
end
def foobar(proc)
proc.call
puts 'foobar'
end
foo
proc 디렉토리가에서 실행하지만 foobar
, 그것은에서 생성 foo
하고 그래서 return
종료 foo
뿐만 아니라, foobar
. Charles Caldwell이 위에서 썼 듯이 GOTO 느낌이 있습니다. 제 생각에는 return
어휘 문맥에서 실행되는 블록에서는 문제가 없지만 다른 문맥에서 실행되는 proc에서 사용될 때 훨씬 덜 직관적입니다.
동작의 차이점 return
은 IMHO 와 2 사이의 가장 중요한 차이점입니다. Proc.new :-)보다 타이핑이 적기 때문에 lambda를 선호합니다.
proc {}
. 이것이 언제 적용되는지 확실하지 않지만 Proc.new를 입력하는 것보다 (약간) 쉽습니다.