Когда использовать лямбду, когда использовать Proc.new?
В Ruby 1.8 есть тонкие различия между proc/lambda 9X_ruby с одной стороны и Proc.new
с другой.
- В чем эти отличия?
- Можете ли вы дать рекомендации, как решить, какой из них выбрать?
- В Ruby 1.9 proc и lambda отличаются. В чем дело?
- Также см. Подробный пост [Различия в потоке управления между Ruby Procs и Lambdas] ( ...
Ответ #1
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Еще одно важное, но тонкое различие между 9X_lambda-functions процессами, созданными с помощью lambda
, и процессами, созданными 9X_lambda-expressions с помощью Proc.new
, заключается в том, как они обрабатывают 9X_generic-lambda оператор return
:
- В процессе, созданном
lambda
, операторreturn
возвращает значение только из самого процесса - В проце, созданном
Proc.new
, операторreturn
немного более удивителен: он возвращает управление не только из процесса, , но и из метода, включающего процесс!
Вот созданный lambda
процесс return
в действии. Он 9X_ruby ведет себя так, как вы, вероятно, ожидаете:
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"
Теперь 9X_lambda то же самое делает Proc.new
созданный процесс return
. Вы 9X_lambda-functions скоро увидите один из тех случаев, когда 9X_lambda-functions Ruby нарушает хваленый принцип наименьшего 9X_proc удивления:
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"
Благодаря этому удивительному 9X_lambda поведению (а также тому, что я меньше печатаю), я 9X_lambda-expressions предпочитаю использовать lambda
, а не Proc.new
при создании 9X_lambda проков.
- @panzi, да, [`proc` эквивалентно` Proc.new`] (http://www.ruby-doc.org/core/classes/K ...
Ответ #2
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Чтобы дать дополнительные пояснения:
Джои 9X_lambdaexpression говорит, что поведение Proc.new
при возврате вызывает 9X_lambda-expressions удивление. Однако, если учесть, что Proc.new 9X_lambda ведет себя как блок, это неудивительно, поскольку 9X_proc именно так ведут себя блоки. с другой стороны, ламбы 9X_lambdaexpression больше похожи на методы.
Это фактически объясняет, почему 9X_lambda-functions Procs гибки, когда дело касается арности 9X_lambda-functions (количества аргументов), а лямбды - нет. Блоки 9X_proc не требуют предоставления всех своих аргументов, но 9X_lambda методы требуют (если не указано значение 9X_ruby по умолчанию). Хотя предоставление лямбда-аргумента 9X_proc по умолчанию не является опцией в Ruby 1.8, теперь 9X_lambda-expressions оно поддерживается в Ruby 1.9 с альтернативным 9X_lambdaexpression синтаксисом лямбда-выражения (как отмечает 9X_lambda-functions webmat):
concat = ->(a, b=2){ "#{a}#{b}" } concat.call(4,5) # => "45" concat.call(1) # => "12"
И Мишель де Маре (OP) неверно говорит 9X_lambda-functions о том, что Procs и лямбда ведут себя одинаково 9X_lambdaexpression с arity в Ruby 1.9. Я убедился, что они 9X_lambda-functions по-прежнему поддерживают поведение начиная 9X_proc с версии 1.8, как указано выше.
Операторы
break
на самом 9X_lambda-functions деле не имеют особого смысла ни в Procs, ни 9X_lambda-functions в лямбдах. В Procs перерыв вернет вас из 9X_generic-lambda Proc.new, который уже был завершен. И нет 9X_lambdaexpression никакого смысла отказываться от лямбды, поскольку 9X_proc это, по сути, метод, и вы никогда не откажетесь 9X_ruby от верхнего уровня метода.
next
, redo
и raise
ведут себя 9X_lambda-functions одинаково как в Procs, так и в лямбдах. В 9X_lambda-functions то время как retry
не допускается ни в том, ни 9X_lambda-expressions в другом случае и вызовет исключение.
И, наконец, никогда 9X_lambda-expressions не следует использовать метод proc
, поскольку 9X_ruby он непоследователен и имеет неожиданное 9X_lambda-functions поведение. В Ruby 1.8 он фактически возвращает 9X_lambda-functions лямбду! В Ruby 1.9 это было исправлено, и 9X_lambda-expressions он возвращает Proc. Если вы хотите создать 9X_lambda Proc, придерживайтесь Proc.new
.
Для получения дополнительной 9X_generic-lambda информации я настоятельно рекомендую O'Reilly 9X_proc Язык программирования Ruby, который является моим источником большей 9X_lambda-expressions части этой информации.
- Начиная с Ruby 2.5, `break` из Procs выз ...
Ответ #3
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Я нашел this page, что показывает разницу между Proc.new
и 9X_lambda-functions lambda
. Согласно странице, единственное отличие 9X_lambda состоит в том, что лямбда строга в отношении 9X_generic-lambda количества принимаемых аргументов, тогда 9X_generic-lambda как Proc.new
преобразует отсутствующие аргументы 9X_generic-lambda в nil
. Вот пример сеанса IRB, иллюстрирующий 9X_lambdaexpression разницу:
irb(main):001:0> l = lambda { |x, y| x + y } => # irb(main):002:0> p = Proc.new { |x, y| x + y } => # irb(main):003:0> l.call "hello", "world" => "helloworld" irb(main):004:0> p.call "hello", "world" => "helloworld" irb(main):005:0> l.call "hello" ArgumentError: wrong number of arguments (1 for 2) from (irb):1 from (irb):5:in `call' from (irb):5 from :0 irb(main):006:0> p.call "hello" TypeError: can't convert nil into String from (irb):2:in `+' from (irb):2 from (irb):6:in `call' from (irb):6 from :0
На странице также рекомендуется 9X_ruby использовать лямбда-выражение, если вы специально 9X_lambda-functions не хотите, чтобы поведение было устойчивым 9X_ruby к ошибкам. Я согласен с этим мнением. Использование 9X_proc лямбды кажется немного более кратким, и 9X_lambdaexpression с такой незначительной разницей, это кажется 9X_lambda-expressions лучшим выбором в средней ситуации.
Что касается 9X_generic-lambda Ruby 1.9, извините, я еще не смотрел в 1.9, но 9X_lambda я не думаю, что они будут настолько сильно 9X_lambda меняться (хотя не верьте мне на слово, кажется, вы 9X_proc слышали о некоторых изменениях, так что 9X_lambda тут я наверное не прав)
- procs также возвращ ...
Ответ #4
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Proc старше, но семантика возврата мне сильно 9X_lambda-functions противоречит (по крайней мере, когда я изучал 9X_generic-lambda язык), потому что:
- Если вы используете proc, вы, скорее всего, используете какую-то функциональную парадигму.
- Proc может вернуться за пределы охватывающей области (см. предыдущие ответы), что в основном является переходом и крайне нефункционально по своей природе.
Lambda функционально безопаснее 9X_lambda-expressions и проще — я всегда использую ее вместо proc.
Ответ #5
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Я не могу много сказать о тонких различиях. Тем 9X_lambdaexpression не менее, я могу отметить, что Ruby 1.9 9X_generic-lambda теперь допускает необязательные параметры 9X_lambda-expressions для лямбда-выражений и блоков.
Вот новый 9X_ruby синтаксис для stabby lambdas в версии 1.9:
stabby = ->(msg='inside the stabby lambda') { puts msg }
В 9X_proc Ruby 1.8 такого синтаксиса не было. Также 9X_lambda-expressions традиционный способ объявления блоков / лямбда-выражений 9X_lambda-expressions не поддерживает необязательные аргументы:
# 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 9X_lambda 1.9, однако, поддерживает необязательные 9X_proc аргументы даже со старым синтаксисом:
l = lambda { |msg = 'inside the regular lambda'| puts msg } #=> # l.call #=> inside the regular lambda l.call('jeez') #=> jeez
Если 9X_ruby вы хотите собрать Ruby1.9 для Leopard или 9X_lambdaexpression Linux, попробуйте this article (бессовестная самореклама).
Ответ #6
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Хороший способ увидеть, что лямбды выполняются 9X_generic-lambda в своей собственной области (как если бы 9X_ruby это был вызов метода), в то время как Procs 9X_ruby можно рассматривать как выполняемые в строке 9X_lambda с вызывающим методом, по крайней мере, это 9X_lambda-expressions хороший способ решить, какой по одному в 9X_lambda каждом случае.
Ответ #7
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Краткий ответ: важно то, что делает return
: лямбда 9X_proc возвращается из себя, а процедура возвращает 9X_lambda-functions из себя И функции, которая ее вызвала.
Менее 9X_proc ясно, почему вы хотите использовать каждый 9X_generic-lambda из них. лямбда - это то, что мы ожидаем 9X_lambdaexpression от вещей в смысле функционального программирования. По 9X_lambda сути, это анонимный метод с автоматически 9X_lambdaexpression привязанной текущей областью видимости. Из 9X_lambda этих двух вам, вероятно, следует использовать 9X_lambda-expressions лямбда.
Proc, с другой стороны, действительно 9X_proc полезен для реализации самого языка. Например, с 9X_ruby ними можно реализовать операторы if или 9X_generic-lambda циклы for. Любой возврат, найденный в процедуре, будет 9X_ruby возвращен из метода, который его вызвал, а 9X_ruby не только из оператора «if». Вот как работают 9X_generic-lambda языки, как работают операторы «если», поэтому 9X_lambdaexpression я предполагаю, что Ruby использует это под 9X_lambdaexpression прикрытием, и они просто раскрыли его, потому 9X_lambda что это казалось мощным.
Это действительно 9X_lambda может понадобиться вам только в том случае, если 9X_generic-lambda вы создаете новые языковые конструкции, такие 9X_proc как циклы, конструкции if-else и т. д.
- лямбда возвращается из себя, а процедура возвращается из себя. И функция, которая ее вызвала, "является явной оши ...
Ответ #8
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Я не заметил никаких комментариев к третьему 9X_ruby методу в квестоне, "proc", который устарел, но 9X_lambda обрабатывается по-другому в 1.8 и 1.9.
Вот 9X_ruby довольно подробный пример, который позволяет 9X_ruby легко увидеть различия между тремя похожими 9X_ruby вызовами:
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 и Proc.new возвращали разные результаты. Однако в 1.9 они ведут себя так же (proc - это псевдоним для Proc.new). http://eigenclass.or ...
Ответ #9
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Closures in Ruby — хороший обзор того, как блоки, лямбда-выражения 9X_generic-lambda и процедуры работают в Ruby с помощью Ruby.
Ответ #10
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
лямбда работает должным образом, как и на 9X_proc других языках.
Проводной Proc.new
удивляет и сбивает 9X_lambda-functions с толку.
Оператор return
в процедуре, созданной 9X_lambdaexpression Proc.new
, вернет управление не только от себя, но 9X_generic-lambda и также от метода, включающего его.
def some_method myproc = Proc.new {return "End."} myproc.call # Any code below will not get executed! # ... end
Вы можете утверждать, что Proc.new
вставляет 9X_ruby код во включающий метод, как и блок. Но 9X_proc Proc.new
создает объект, а блок является частью объекта.
Есть 9X_lambda-functions еще одно различие между лямбдой и Proc.new
, которое 9X_ruby заключается в обработке (неправильных) аргументов. lambda 9X_proc жалуется на это, в то время как Proc.new
игнорирует 9X_ruby лишние аргументы или считает отсутствие 9X_lambda аргументов нулевым.
irb(main):021:0> l = -> (x) { x.to_s } => # irb(main):022:0> p = Proc.new { |x| x.to_s} => # 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 `
' 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 `
' irb(main):050:0> p.call 1, 2 => "1"
Кстати, proc
в Ruby 1.8 создает 9X_lambdaexpression лямбду, а в Ruby 1.9+ ведет себя как Proc.new
, что 9X_lambda-functions действительно сбивает с толку.
Ответ #11
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Чтобы уточнить ответ Аккордеона:
Обратите 9X_lambda-functions внимание, что Proc.new
создает прок, передавая блок. Я 9X_generic-lambda считаю, что lambda {...}
анализируется как своего рода 9X_ruby литерал, а не вызов метода, который передает 9X_lambdaexpression блок. return
выполнение изнутри блока, прикрепленного 9X_lambda-functions к вызову метода, будет возвращаться из метода, а 9X_lambda-expressions не из блока, и случай Proc.new
является примером 9X_lambda-expressions этого в игре.
(Это 1.8. Я не знаю, как это 9X_ruby переводится в 1.9.)
Ответ #12
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Я немного опоздал с этим, но есть одна замечательная, но 9X_lambda малоизвестная вещь о Proc.new
, которая вообще не 9X_generic-lambda упоминается в комментариях. Согласно documentation:
Proc::new
может 9X_proc быть вызван без блока только внутри метода 9X_lambda-expressions с присоединенным блоком, и в этом случае 9X_proc этот блок преобразуется в объектProc
.
Тем не менее, Proc.new
позволяет связывать 9X_ruby методы получения результатов:
def m1 yield 'Finally!' if block_given? end def m2 m1 &Proc.new end m2 { |e| puts e } #⇒ Finally!
Ответ #13
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Стоит подчеркнуть, что return
в процедуре возвращает 9X_proc из лексически включающего метода, то есть 9X_lambdaexpression метода, в котором была создана процедура, не метода, вызвавшего процедуру . Это следствие 9X_proc закрывающего свойства procs. Итак, следующий 9X_generic-lambda код ничего не выводит:
def foo proc = Proc.new{return} foobar(proc) puts 'foo' end def foobar(proc) proc.call puts 'foobar' end foo
Хотя процедура выполняется 9X_lambda-functions в foobar
, она была создана в foo
, поэтому return
выходит 9X_lambda-expressions из foo
, а не только из foobar
. Как писал выше Чарльз 9X_lambda-functions Колдуэлл, в нем есть чувство GOTO. На мой 9X_generic-lambda взгляд, return
подходит для блока, который выполняется 9X_lambda-functions в его лексическом контексте, но гораздо 9X_lambda-expressions менее интуитивно понятен при использовании 9X_generic-lambda в процессе, который выполняется в другом 9X_lambda-expressions контексте.
Ответ #14
Ответ на вопрос: Когда использовать лямбду, когда использовать Proc.new?
Разница в поведении с return
ИМХО является самым 9X_generic-lambda важным отличием между 2. Я также предпочитаю 9X_lambda лямбду, потому что она меньше печатает, чем 9X_ruby Proc.new :-)
- Для обновления: теперь процессы можно создавать ...
-
4
-
3
-
8
-
3
-
3
-
22
-
14
-
4
-
14
-
13
-
12
-
8
-
9
-
11
-
14
-
4
-
4
-
4
-
4
-
5
-
5
-
3
-
6
-
4
-
9
-
7
-
4
-
7
-
7
-
10
-
7
-
10
-
4
-
22
-
4
-
9
-
11
-
4
-
3
-
8
-
11
-
6
-
5
-
6
-
26
-
3
-
4
-
5
-
10
-
8