何时使用lambda,何时使用Proc.new?

在Ruby 1.8中,一方面proc / lambda和另一方面 Proc.new 之间存在细微差别。

  • 这些差异是什么?
  • 您可以提供关于如何决定选择哪一个的准则
  • 在Ruby 1.9中,proc和lambda是不同的。什么是交易?
0
额外 编辑
意见: 1
你已经接受了只说proc和lambda有什么区别的答案,而你的问题的标题是何时使用这些东西
额外 作者 Shri,
另请参阅:Matz和Flanagan编写的Ruby编程语言手册,全面介绍了该主题。 proc的行为就像一个块产出语义,其中lambda表现得像一个方法 - 方法调用语义。还返回,休息,等。所有的行为在不同的lambda表达式中都有差异
额外 作者 Gishu,
建议不要在发布网站中使用CEWP,原因很多,比如它将URL作为绝对URL存储,没有版本历史记录等,更多信息请参见 andrewconnell.com/blog/archive/2009/02/01 /…
额外 作者 Greg,
以前没有听说过,但这是有道理的。这是我们试图采取捷径的努力之一。在这篇文章之后不久,我们废弃了这条路径,决定开发一个专门针对类别的布局,而不是使用视图页面。
额外 作者 Daemin,
额外 作者 Akshay Rawat,

13 答案

尝试使用SP Designer检查它。

2
额外
那么工作。这很奇怪,因为我们之前不需要检查出其他10组变更。由于视图没有内容批准,并且无法通过界面完成,所以我没有在SPD中执行此操作。谢谢!
额外 作者 Daemin,

我发现了这个页面,它显示了 Proc.new 和<�代码> lambda 。根据页面,唯一的区别是lambda严格限制它接受的参数数量,而 Proc.new 将缺少的参数转换为 nil 。以下是IRB会话的一个示例,说明不同之处:

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

The page also recommends using lambda unless you specifically want the error tolerant behavior. I agree with this sentiment. Using a lambda seems a tad more concise, and with such an insignificant difference, it seems the better choice in the average situation.

As for ruby 1.9, sorry, I haven't looked into 1.9 yet, but I don't imagine they would change it all that much (don't take my word for it though, it seems you have heard of some changes, so I am probably wrong there).

0
额外
特效也不同于lambda。
额外 作者 Cam,
“”“Proc.new将缺少的参数转换为零”“”Proc.new也忽略了额外的参数(当然,lambda抱怨这个错误)。
额外 作者 weakish,

return 行为的差异是恕我直言,这是2之间最重要的区别。我也更喜欢lambda,因为它的输入少于Proc.new :-)

0
额外
要更新:现在可以使用 proc {} 创建procs。我不确定什么时候生效,但它比输入Proc.new更轻松。
额外 作者 aceofbassgreg,

详细阐述手风琴家的回应:

请注意, Proc.new 通过传递一个块来创建一个proc。我相信 lambda {...} 被解析为一种文字,而不是通过块传递的方法调用。从附加到方法调用的块中返回 return 将从该方法返回,而不是块,并且 Proc.new 情况就是这种情况的一个例子。

(这是1.8,我不知道这是怎么翻译成1.9。)

0
额外

我在这方面有点迟,但关于 Proc.new 有一点但很少知道,但在评论中没有提到。通过文档

Proc :: new 可能只在带有附加块的方法中没有块,在这种情况下块被转换为 Proc / strong>对象。

也就是说, Proc.new 允许链式产生方法:

def m1
  yield 'Finally!' if block_given?
end

def m2
  m1 &Proc.new
end

m2 { |e| puts e } 
#? Finally!
0
额外
有趣的是,它和在 def 中声明一个&block 参数的做法是一样的,但不需要在def arg列表中这样做。
额外 作者 jrochkind,

看到它的一个好方法是lambda在他们自己的范围内执行(就像它是一个方法调用一样),而Procs可以被视为与调用方法内联执行,至少这是决定使用哪一个的好方法在每种情况下。

0
额外

我不能说很多细微的差异。不过,我可以指出,Ruby 1.9现在允许lambdas和块的可选参数。

下面是1.9下的stabby lambda的新语法:

stabby = ->(msg='inside the stabby lambda') { puts msg }

Ruby 1.8没有这种语法。声明块/ lambda表达式的传统方式也不支持可选参数:

# 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 }
#=> #
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

If you wanna build Ruby1.9 for Leopard or Linux, check out this article (shameless self promotion).

0
额外
你没有在块中显示默认参数,只有lambda表达式
额外 作者 iconoclast,
lambda中的可选参数是非常必要的,我很高兴他们在1.9中添加了它。我认为块也可以有可选参数(1.9)?
额外 作者 mpd,

提供进一步的说明:

Joey说 Proc.new 的返回行为令人惊讶。但是,当你认为Proc.new的行为像一个块时,这并不奇怪,因为这正是块的行为方式。另一方面,羔羊的行为更像方法。

这实际上解释了为什么Procs在灵活性(参数数量)方面很灵活,而lambda则不是。块不需要提供所有的参数,但方法可以(除非提供默认值)。虽然在Ruby 1.8中提供lambda参数默认值不是选项,但现在在Ruby 1.9中支持替代lambda语法(如webmat所示):

concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1)   # => "12"

而Michiel de Mare(OP)对于Proc和lambda在Ruby 1.9中的表现与Arity相同是不正确的。我已经证实,他们仍然保持从上面指定的1.8的行为。

break statements don't actually make much sense in either Procs or lambdas. In Procs, the break would return you from Proc.new which has already been completed. And it doesn't make any sense to break from a lambda since it's essentially a method, and you would never break from the top level of a method.

next, redo, and raise behave the same in both Procs and lambdas. Whereas retry is not allowed in either and will raise an exception.

最后,不应该使用 proc 方法,因为它不一致并且具有意外行为。在Ruby 1.8中,它实际上返回一个lambda!在Ruby 1.9中,它已经被修复并且返回一个Proc。如果您想创建一个Proc,请使用 Proc.new

有关更多信息,我强烈建议O'Reilly的 Ruby编程语言,这是我获取大多数此类信息的来源。

0
额外
“”“然而,当你认为Proc.new的行为类似于块时,这并不奇怪,因为这正是块的行为方式。”“”< - 块是对象的一部分,而Proc.new创建一个对象。 lambda和Proc.new都创建一个类为Proc的对象,为什么diff?
额外 作者 weakish,

使用 lambda 创建的procs和使用 Proc.new 创建的procs之间的另一个重要但很细微的区别是它们如何处理 return 语句:

  • In a lambda-created proc, the return statement returns only from the proc itself
  • In a Proc.new-created proc, the return statement is a little more surprising: it returns control not just from the proc, but also from the method enclosing the 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 做同样的事情。你将会看到Ruby打破了最令人惊讶的原则之一:

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 来覆盖 Proc.new

0
额外
额外 作者 ma11hew28,
我相信一个主要的区别是,当您提供缺少/额外参数时, Proc 不会抛出错误,而 lambda 会抛出错误数量的参数错误
额外 作者 Edmund,
@mattdipasquale在我的测试中, proc 的行为像 lambda ,而不像 Proc.new 关于return语句。这意味着ruby doc是不准确的。
额外 作者 Kelvin,
@mattdipasquale对不起,我只是一半的权利。 proc 在1.8中的作用类似于 lambda ,但在1.9中的作用类似于 Proc.new 。见Peter Wagenet的答案。
额外 作者 Kelvin,
然后还有 proc 方法。它只是 Proc.new 的缩写吗?
额外 作者 panzi,
为什么这种“令人惊讶”的行为?一个 lambda 是一个匿名方法。由于它是一种方法,它会返回一个值,并且调用它的方法可以随意执行它,包括忽略它并返回不同的值。一个 Proc 就像是粘贴在一个代码片段中。它不像一种方法。所以当 Proc 中发生返回时,这只是调用它的方法的代码的一部分。
额外 作者 Arcolye,
正如Arcolye所指出的,“Ruby中的Procs放在代码片段中,而不是方法”。从 robertsosinski.com/2008/12/ 21 /&hellip; 。所以它就像是回报本身。
额外 作者 Pietro,

我没有注意到任何关于第三种方法的评论,“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
0
额外
我认为镐可以在某个脚注的某个地方说proc是有效的depricated或什么的。我没有确切的页码。
额外 作者 dertoni,
@banister: proc 在1.8中返回一个lambda;现在已经确定要返回一个1.9的proc - 但这是一个突破性的变化;因此不推荐再使用
额外 作者 Gishu,
你在哪里读过 proc 已被弃用?
额外 作者 horseyguy,
Matz曾表示他计划弃用它,因为proc和Proc.new返回不同的结果令人困惑。在1.9中,它们的行为相同(proc是Proc.new的别名)。 eigenclass.org/hiki/Changes+in+Ruby+1.9#l47
额外 作者 Dave Rapin,

简短回答:重要的是 return 所做的事情:lambda返回自身,并且proc返回自身以及调用它的函数。

不太清楚的是为什么你要使用每个。 lambda是我们期望事物在功能编程意义上应该做的。它基本上是一个自动绑定当前作用域的匿名方法。在这两者中,lambda是你应该使用的那个。

另一方面,Proc对于实现语言本身非常有用。例如,你可以实现“if”语句或“for”循环。在proc中找到的任何返回将从调用它的方法返回,而不仅仅是“if”语句。这就是语言的工作原理,“if”语句的工作原理,所以我的猜测是Ruby在封面下使用它,他们只是将它暴露出来,因为它看起来很强大。

如果你正在创建新的语言结构,比如循环,if-else结构等,你只会真的需要这个。

0
额外

Understanding ruby Blocks, Procs and Lambdas by Robert Sosinski clearly explains these programming concepts and reinforces the explanations with example code. Method objects are related and covered as well.

0
额外

lambda按预期工作,就像其他语言一样。

有线的 Proc.new 令人惊讶且令人困惑。

Proc.new 创建的proc中的 return 语句不仅会从本身返回控制,还会从包含它的方法返回 。

def some_method
  myproc = Proc.new {return "End."}
  myproc.call

  # Any code below will not get executed!
  # ...
end

您可以争辩说, Proc.new 将代码插入封闭方法中,就像块一样。 但 Proc.new 会创建一个对象,而block则是 的一部分。

而lambda和 Proc.new 之间还有另一个区别,即它们处理(错误)参数。 lambda抱怨它,而 Proc.new 忽略额外的参数或将参数缺失视为零。

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"

BTW, proc in ruby 1.8 creates a lambda, while in ruby 1.9+ behaves like Proc.new, which is really confusing.

0
额外