[ruby] 루비에서 proc와 람다의 차이점은 무엇입니까?

그리고 언제 다른 것을 사용하지 않습니까?



답변

한 가지 차이점은 인수를 처리하는 방식에 있습니다. 사용 PROC 만들기 proc {}Proc.new {}동일합니다. 그러나를 사용 lambda {}하면 전달 된 인수 수를 확인하는 proc이 제공됩니다. 보낸 사람 ri Kernel#lambda:

상당 Proc.new 결과 PROC 제외하고는 호출시에 전달 된 파라미터의 개수를 확인 개체.

예를 들면 :

p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)

또한 Ken이 지적한 것처럼 return람다 내부를 사용 하면 해당 람다의 값이 반환되지만 returnproc에서 사용하면 둘러싸는 블록에서 반환됩니다.

lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return

따라서 대부분의 빠른 사용법은 동일하지만 자동 엄격한 인수 검사 (때로는 디버깅에 도움이 될 수 있음)를 원하거나 return명령문을 사용하여 proc 값을 반환 해야하는 경우을 사용하십시오 lambda.


답변

procs와 lambdas의 실제 차이점은 제어 흐름 키워드와 관련이 있습니다. 나는에 대해 이야기하고 return, raise, break, redo, retry그 제어 워드 – 등. proc에 return 문이 있다고 가정 해 봅시다. proc을 호출하면 proc을 덤프 할뿐만 아니라 다음과 같은 엔 클로징 메소드에서 돌아옵니다.

def my_method
  puts "before proc"
  my_proc = Proc.new do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method

shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc

puts우리가 proc을 호출했을 때 return메소드 내에서 우리를 메소드에서 버렸기 때문에 메소드 의 마지막 은 실행되지 않았습니다 . 그러나 proc을 람다로 변환하면 다음과 같은 결과가 나타납니다.

def my_method
  puts "before proc"
  my_proc = lambda do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc

람다 내 리턴은 람다 자체에서 우리를 덤프하고 엔 클로징 메소드는 계속 실행됩니다. 제어 흐름 키워드가 procs와 람다 내에서 처리되는 방식은 주요 차이점입니다.


답변

두 가지 주요 차이점 만 있습니다.

  • 먼저 a lambda는 전달 된 인수 수를 확인하지만 a proc는 그렇지 않습니다. 즉 lambda, 잘못된 수의 인수를 전달하면 오류가 발생하지만 proc예기치 않은 인수는 무시하고 nil누락 된 인수를 지정 합니다.
  • 둘째, lambda반환 할 때 제어를 호출 메서드로 다시 전달합니다. 때 proc반환 할 때 호출 방법 등을 거치지 않고, 그래서 즉시 않습니다.

이것이 어떻게 작동하는지 보려면 아래 코드를 살펴보십시오. 우리의 첫 번째 메소드는 proc; 두 번째는 a를 호출합니다 lambda.

def batman_ironman_proc
  victor = Proc.new { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_proc # prints "Batman will win!"

def batman_ironman_lambda
  victor = lambda { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_lambda # prints "Iron Man will win!"

proc“배트맨이 이길 것입니다!” 라는 말을 참조하십시오 . 이는 batman_ironman_proc 메소드로 돌아 가지 않고 즉시 리턴되기 때문입니다.

lambda그러나 우리 는 호출 된 후에 메소드로 되돌아가므로 메소드는 마지막으로 평가 한 코드를 리턴합니다 : “Iron Man이 이길 것입니다!”


답변

# 예

p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p)              # The '&' tells ruby to turn the proc into a block 

proc = Proc.new { puts "Hello World" }
proc.call

# 람다 예제

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

Procs와 Lambdas의 차이점

procs와 lambdas의 차이점에 들어가기 전에 둘 다 Proc 객체라는 것을 언급하는 것이 중요합니다.

proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }

proc.class # returns 'Proc'
lam.class  # returns 'Proc'

그러나 람다는 procs의 다른 ‘맛’입니다. 이 약간의 차이는 객체를 반환 할 때 표시됩니다.

proc   # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam    # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'

1. 람다는 인수의 수를 확인하지만 procs는 그렇지 않습니다

lam = lambda { |x| puts x }    # creates a lambda that takes 1 argument
lam.call(2)                    # prints out 2
lam.call                       # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3)                # ArgumentError: wrong number of arguments (3 for 1)

반대로, procs는 잘못된 수의 인수를 전달했는지는 신경 쓰지 않습니다.

proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2)                   # prints out 2
proc.call                      # returns nil
proc.call(1,2,3)               # prints out 1 and forgets about the extra arguments

2. Lambdas와 procs는 ‘return’키워드를 다르게 취급합니다.

람다 내부의 ‘반환’은 람다 코드 외부에서 코드를 트리거합니다.

def lambda_test
  lam = lambda { return }
  lam.call
  puts "Hello world"
end

lambda_test                 # calling lambda_test prints 'Hello World'

proc 내부의 ‘return’은 proc이 실행되는 메소드 외부의 코드를 트리거합니다.

def proc_test
  proc = Proc.new { return }
  proc.call
  puts "Hello world"
end

proc_test                 # calling proc_test prints nothing

그리고 언제 어떤 쿼리를 사용해야합니까? 그가 언급 한대로 @jtbandes를 따를 것입니다.

따라서 대부분의 빠른 사용법은 동일하지만 자동 엄격한 인수 검사 (때로는 디버깅에 도움이 될 수 있음)를 원하거나 return 문을 사용하여 proc 값을 반환 해야하는 경우 lambda를 사용하십시오.

원래 여기에 게시


답변

일반적으로 람다는 메서드와 비슷하기 때문에 procs보다 직관적입니다. 그들은 arity에 대해 매우 엄격하며 return을 호출하면 종료됩니다. 이런 이유로, 많은 루비 스트들은 람다가 procs의 특정 기능을 필요로하지 않는 한 가장 먼저 선택합니다.

발동 : 클래스의 객체 Proc. 블록과 마찬가지로 이들은 정의 된 범위에서 평가됩니다.
람다 : 클래스의 객체 Proc이지만 일반 프로세스와 미묘하게 다릅니다. 그것들은 블록 및 procs와 같은 클로저이므로 정의 된 범위에서 평가됩니다.

Proc 만들기

a = Proc.new { |x| x 2 }

람다 만들기

b = lambda { |x| x 2 }


답변

이것을 이해하는 또 다른 방법이 있습니다.

블록은 객체의 메소드 호출에 대한 호출에 첨부 된 코드 덩어리입니다. 아래 예제에서 self는 Rails 프레임 워크의 ActionView :: Base에서 상속되는 익명 클래스의 인스턴스입니다 (자체에는 많은 도우미 모듈이 포함됨). 카드는 우리가 스스로 부르는 방법입니다. 메소드에 인수를 전달한 다음 항상 메소드 호출 끝에 블록을 첨부합니다.

self.card :contacts do |c|
  // a chunk of valid ruby code
end

자, 우리는 코드 덩어리를 메소드에 전달합니다. 그러나이 블록을 어떻게 사용합니까? 한 가지 옵션은 코드 청크를 객체로 변환하는 것입니다. 루비는 코드 덩어리를 객체로 변환하는 세 가지 방법을 제공합니다

# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2

# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2

# & as the last method argument with a local variable name
def add(&block)
end

위의 방법에서 &는 메소드에 전달 된 블록을 객체로 변환하고 해당 객체를 로컬 변수 블록에 저장합니다. 실제로 람다 및 Proc.new와 동일한 동작을 가지고 있음을 보여줄 수 있습니다.

def add(&block)
  block
end

l3 = add { |a| a + 1 }
l3.call(1)
=> 2

이건 중요하다. 블록을 메소드에 전달하고 &를 사용하여 변환하면 생성 된 객체가 Proc.new를 사용하여 변환을 수행합니다.

옵션으로 “proc”를 사용하지 않았습니다. Ruby 1.8이기 때문에 람다와 동일하며 Ruby 1.9에서는 Proc.new와 동일하며 모든 Ruby 버전에서는 피해야합니다.

그렇다면 람다와 Proc.new의 차이점은 무엇입니까?

먼저 매개 변수 전달 측면에서 람다는 메서드 호출처럼 동작합니다. 잘못된 수의 인수를 전달하면 예외가 발생합니다. 반대로 Proc.new는 병렬 할당처럼 동작합니다. 사용되지 않은 모든 인수는 nil로 변환됩니다.

> l = lambda {|a,b| puts "#{a} + #{b}" }
 => #<Proc:0x007fbffcb47e40@(irb):19 (lambda)> 
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)

> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0@(irb):21> 
> l2.call(1)
1 + 

둘째, lambda와 Proc.new는 return 키워드를 다르게 처리합니다. Proc.new 내부에서 리턴을 수행하면 실제로는 둘러싸는 메소드, 즉 주변 컨텍스트에서 리턴됩니다. 람다 블록에서 돌아올 때는 엔 클로징 방법이 아니라 블록에서 반환됩니다. 기본적으로 블록 호출에서 나가고 나머지 엔 클로징 메소드로 실행을 계속합니다.

> def add(a,b)
  l = Proc.new { return a + b}
  l.call
  puts "now exiting method"
end
> add(1,1)
=> 2  # NOTICE it never prints the message "now exiting method"

> def add(a,b)
  l = lambda { return a + b }
  l.call
  puts "now exiting method"
end
> add(1,1)
=> now exiting method  # NOTICE this time it prints the message "now exiting method"

왜 이런 행동 차이가 있습니까? 그 이유는 Proc.new를 사용하면 둘러싸는 방법의 맥락에서 반복자를 사용하고 논리적 결론을 도출 할 수 있기 때문입니다. 이 예를보십시오 :

> def print(max)
  [1,2,3,4,5].each do |val|
    puts val
    return if val > max
  end
end
> print(3)
1
2
3
4

반복자 내부에서 return을 호출하면 엔 클로징 메소드에서 리턴 될 것으로 예상합니다. 반복자에 전달 된 블록은 Proc.new를 사용하여 객체로 변환되므로 return을 사용할 때 엔 클로징 메서드를 종료합니다.

람다는 익명의 메소드로 생각할 수 있으며 개별 코드 블록을 메소드처럼 취급 할 수있는 객체로 분리합니다. 궁극적으로 람다는 익명의 방법으로 동작하고 Proc.new는 인라인 코드로 동작한다고 생각합니다.


답변

루비 가이드에 대한 유용한 게시물 : 블록, 프로세서 및 람다

람다는 람다 자체에서 돌아 오는 반면 procs는 현재 방법에서 돌아옵니다.

Procs는 올바른 수의 인수에 신경 쓰지 않지만 람다는 예외를 발생시킵니다.