Одно из различий заключается в том, как они обрабатывают аргументы. Создание процедуры с использованием proc {}и Proc.new {}эквивалентны. Однако использование lambda {}дает вам прок, который проверяет количество аргументов, переданных ему. От 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)
Кроме того, как указывает Кен, использование returnвнутри лямбды возвращает значение этой лямбды, но использование returnв процедуре возвращает из вмещающего блока.
Так что для большинства быстрых применений они одинаковы, но если вам нужна автоматическая строгая проверка аргументов (которая иногда может также помочь с отладкой), или если вам нужно использовать returnинструкцию для возврата значения proc, используйте lambda.
Правильно ли будет сказать, что лямбды очень похожи на методы (проверьте аргументы и return будет возвращать их), в то время как процы очень похожи на блоки (аргументы не проверяются, и возврат будет возвращаться из содержащего метода или лямбды)?
pedz
Я был к Богу, знает, сколько веб-сайтов и статей к настоящему времени, и никто, кажется, не говорит о полезности Procs против методов против лямбд. Каждое объяснение просто дает потрясающую информацию о том, как возвращаемые значения и т. Д. Различаются, но не о том, почему это важно. Пока я должен сделать вывод, что это дизайнерский беспорядок в Ruby.
ankush981
76
Реальная разница между процессами и лямбдами связана с ключевыми словами потока управления. Я говорю о том return, raise, break, redo, и retryт.д. - тех управляющих словах. Допустим, у вас есть инструкция возврата в процедуре. Когда вы вызываете ваш proc, он не только выкинет вас из него, но также вернет метод включения, например:
Финал putsв методе никогда не выполнялся, так как, когда мы вызывали наш метод, returnвнутри него было исключено из метода. Однако, если мы конвертируем наш proc в лямбду, мы получим следующее:
def my_method
puts "before proc"
my_proc = lambda do
puts "inside proc"returnend
my_proc.call
puts "after proc"end
my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
Возвращение внутри лямбды только выводит нас из самой лямбды, и метод включения продолжает выполняться. То, как ключевые слова потока управления обрабатываются в рамках процедур и лямбда-выражений, является основным отличием между ними.
Во-первых, a lambdaпроверяет количество аргументов, переданных ему, а a proc- нет. Это означает, что a lambdaвыдаст ошибку, если вы передадите ей неправильное количество аргументов, тогда как a procпроигнорирует неожиданные аргументы и назначит nilлюбые, которые отсутствуют.
Во-вторых, когда lambdaвозвращается, он передает управление обратно вызывающему методу; когда procвозвращается, он делает это немедленно, не возвращаясь к вызывающему методу.
Чтобы увидеть, как это работает, взгляните на код ниже. Наш первый метод вызывает proc; второй зовет 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метод возвращается к методу после вызова, поэтому метод возвращает последний код, который он оценивает: «Железный человек победит!»
1. Лямбды проверяют количество аргументов, а процы - нет
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)
Напротив, процессорам все равно, если им передано неправильное количество аргументов.
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
'return' внутри лямбда-кода запускает код прямо за пределами лямбда-кода
И чтобы ответить на ваш другой запрос, какой использовать и когда? Я буду следовать за @jtbandes, как он упомянул
Так что для большинства быстрых применений они одинаковы, но если вы хотите автоматическую строгую проверку аргументов (которая иногда может также помочь с отладкой), или если вам нужно использовать инструкцию return для возврата значения proc, используйте lambda.
Вообще говоря, лямбды более интуитивно понятны, чем проки, потому что они больше похожи на методы. Они довольно строги в отношении арности и просто выходят, когда вы вызываете return. По этой причине многие Rubyists используют лямбды в качестве первого выбора, если они не нуждаются в специфических особенностях процедур.
Procs: объекты класса Proc. Как и блоки, они оцениваются в области, в которой они определены.
Лямбды: также объекты класса, Procно немного отличающиеся от обычных процедур. Это замыкания, подобные блокам и процессам, и поэтому они оцениваются в области, в которой они определены.
a = proc { |x| x 2 }такой же какa = Proc.new { |x| x 2 }
lacostenycoder
1
Вот еще один способ понять это.
Блок - это кусок кода, прикрепленный к вызову метода объекта. В приведенном ниже примере self является экземпляром анонимного класса, унаследованного от ActionView :: Base в платформе Rails (который сам включает в себя множество вспомогательных модулей). карта - это метод, который мы называем собой. Мы передаем аргумент методу, а затем всегда присоединяем блок к концу вызова метода:
self.card :contacts do|c|// a chunk of valid ruby code
end
Итак, мы передаем кусок кода методу. Но как мы можем использовать этот блок? Один из вариантов - преобразовать кусок кода в объект. Ruby предлагает три способа конвертировать кусок кода в объект
# 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 namedef 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 ведет себя как параллельное присваивание. Все неиспользованные аргументы преобразуются в ноль:
> l = lambda {|a,b| puts "#{a} + #{b}"}=>#<Proc:0x007fbffcb47e40@(irb):19 (lambda)> > l.call(1)ArgumentError: wrong number of arguments (1for2)> 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
returnif val > max
endend> print(3)1234
Мы ожидаем, что когда мы вызовем return внутри итератора, он вернется из включающего метода. Помните, что блоки, переданные итераторам, преобразуются в объекты с помощью Proc.new, и поэтому, когда мы используем return, он выходит из метода включения.
Вы можете думать о лямбдах как об анонимных методах, они изолируют отдельные блоки кода в объект, который можно рассматривать как метод. В конечном счете, думайте, что лямбда ведет себя как аномный метод, а Proc.new ведет себя как встроенный код.
Различия между proc и lambda в том, что proc - это просто копия кода с заменяемыми аргументами по очереди, тогда как lambda - это функция, как и в других языках. (поведение возврата, проверка аргументов)
return
выражение возвращает вproc
сравнении сlambda
.Ответы:
Одно из различий заключается в том, как они обрабатывают аргументы. Создание процедуры с использованием
proc {}
иProc.new {}
эквивалентны. Однако использованиеlambda {}
дает вам прок, который проверяет количество аргументов, переданных ему. Отri Kernel#lambda
:Пример:
Кроме того, как указывает Кен, использование
return
внутри лямбды возвращает значение этой лямбды, но использованиеreturn
в процедуре возвращает из вмещающего блока.Так что для большинства быстрых применений они одинаковы, но если вам нужна автоматическая строгая проверка аргументов (которая иногда может также помочь с отладкой), или если вам нужно использовать
return
инструкцию для возврата значения proc, используйтеlambda
.источник
Реальная разница между процессами и лямбдами связана с ключевыми словами потока управления. Я говорю о том
return
,raise
,break
,redo
, иretry
т.д. - тех управляющих словах. Допустим, у вас есть инструкция возврата в процедуре. Когда вы вызываете ваш proc, он не только выкинет вас из него, но также вернет метод включения, например:Финал
puts
в методе никогда не выполнялся, так как, когда мы вызывали наш метод,return
внутри него было исключено из метода. Однако, если мы конвертируем наш proc в лямбду, мы получим следующее:Возвращение внутри лямбды только выводит нас из самой лямбды, и метод включения продолжает выполняться. То, как ключевые слова потока управления обрабатываются в рамках процедур и лямбда-выражений, является основным отличием между ними.
источник
Есть только два основных отличия.
lambda
проверяет количество аргументов, переданных ему, а aproc
- нет. Это означает, что alambda
выдаст ошибку, если вы передадите ей неправильное количество аргументов, тогда как aproc
проигнорирует неожиданные аргументы и назначитnil
любые, которые отсутствуют.lambda
возвращается, он передает управление обратно вызывающему методу; когдаproc
возвращается, он делает это немедленно, не возвращаясь к вызывающему методу.Чтобы увидеть, как это работает, взгляните на код ниже. Наш первый метод вызывает
proc
; второй зоветlambda
.Посмотрите, как
proc
написано «Бэтмен победит!», Потому что он возвращается немедленно, не возвращаясь к методу batman_ironman_proc.Однако наш
lambda
метод возвращается к методу после вызова, поэтому метод возвращает последний код, который он оценивает: «Железный человек победит!»источник
# Proc Примеры
# Лямбда Примеры
Различия между процами и лямбдами
Прежде чем перейти к различиям между процессами и лямбдами, важно упомянуть, что они оба являются объектами Proc.
Однако лямбды - это другой «вкус» проков. Эта небольшая разница проявляется при возврате предметов.
1. Лямбды проверяют количество аргументов, а процы - нет
Напротив, процессорам все равно, если им передано неправильное количество аргументов.
2. Lambdas и procs по-разному обрабатывают ключевое слово return
'return' внутри лямбда-кода запускает код прямо за пределами лямбда-кода
'return' внутри proc вызывает код вне метода, в котором выполняется proc
И чтобы ответить на ваш другой запрос, какой использовать и когда? Я буду следовать за @jtbandes, как он упомянул
Первоначально опубликовано здесь
источник
Вообще говоря, лямбды более интуитивно понятны, чем проки, потому что они больше похожи на методы. Они довольно строги в отношении арности и просто выходят, когда вы вызываете return. По этой причине многие Rubyists используют лямбды в качестве первого выбора, если они не нуждаются в специфических особенностях процедур.
Procs: объекты класса
Proc
. Как и блоки, они оцениваются в области, в которой они определены. Лямбды: также объекты класса,Proc
но немного отличающиеся от обычных процедур. Это замыкания, подобные блокам и процессам, и поэтому они оцениваются в области, в которой они определены.Создание Proc
Создание лямбды
b = lambda { |x| x 2
}источник
a = proc { |x| x 2 }
такой же какa = Proc.new { |x| x 2 }
Вот еще один способ понять это.
Блок - это кусок кода, прикрепленный к вызову метода объекта. В приведенном ниже примере self является экземпляром анонимного класса, унаследованного от ActionView :: Base в платформе Rails (который сам включает в себя множество вспомогательных модулей). карта - это метод, который мы называем собой. Мы передаем аргумент методу, а затем всегда присоединяем блок к концу вызова метода:
Итак, мы передаем кусок кода методу. Но как мы можем использовать этот блок? Один из вариантов - преобразовать кусок кода в объект. Ruby предлагает три способа конвертировать кусок кода в объект
В приведенном выше методе & преобразует блок, переданный методу, в объект и сохраняет этот объект в блоке локальной переменной. Фактически, мы можем показать, что он ведет себя так же, как лямбда и Proc.new:
Это важно. Когда вы передаете блок методу и конвертируете его с помощью &, создаваемый им объект использует Proc.new для конвертации.
Обратите внимание, что я избегал использования «proc» в качестве опции. Это потому, что это Ruby 1.8, он такой же, как лямбда, а в Ruby 1.9 он такой же, как Proc.new, и во всех версиях Ruby его следует избегать.
Итак, вы спросите, в чем разница между лямбда и Proc.new?
Во-первых, с точки зрения передачи параметров, лямбда ведет себя как вызов метода. Это вызовет исключение, если вы передадите неверное количество аргументов. Напротив, Proc.new ведет себя как параллельное присваивание. Все неиспользованные аргументы преобразуются в ноль:
Во-вторых, lambda и Proc.new обрабатывают ключевое слово return по-разному. Когда вы делаете возврат внутри Proc.new, он фактически возвращается из метода включения, то есть из окружающего контекста. Когда вы возвращаетесь из лямбда-блока, он просто возвращается из блока, а не из-за метода включения. По сути, он выходит из вызова в блок и продолжает выполнение с остальной частью включающего метода.
Так почему такая поведенческая разница? Причина в том, что с Proc.new мы можем использовать итераторы внутри контекста вложенных методов и делать логические выводы. Посмотрите на этот пример:
Мы ожидаем, что когда мы вызовем return внутри итератора, он вернется из включающего метода. Помните, что блоки, переданные итераторам, преобразуются в объекты с помощью Proc.new, и поэтому, когда мы используем return, он выходит из метода включения.
Вы можете думать о лямбдах как об анонимных методах, они изолируют отдельные блоки кода в объект, который можно рассматривать как метод. В конечном счете, думайте, что лямбда ведет себя как аномный метод, а Proc.new ведет себя как встроенный код.
источник
Полезный пост на рубиновых путеводителях: блоки, процы и лямбды
источник
Различия между proc и lambda в том, что proc - это просто копия кода с заменяемыми аргументами по очереди, тогда как lambda - это функция, как и в других языках. (поведение возврата, проверка аргументов)
источник