为什么Enumerable#detect需要一个Proc / lambda?

时间:2014-01-02 12:50:58

标签: ruby lambda detect enumerable proc

Enumerable#detect返回块计算结果为true的数组的第一个值。它有一个可选参数,需要响应call并在这种情况下被调用,返回其值。所以,

(1..10).detect(lambda{ "none" }){|i| i == 11} #=> "none"

为什么我们需要lambda?为什么我们不直接传递默认值,因为(在我的测试中)lambda无论如何都不能有任何参数?像这样:

(1..10).detect("none"){|i| i == 11} #=> "none"

5 个答案:

答案 0 :(得分:5)

与Ruby中的所有内容一样,“最小意外原则”适用。当然,这并不是说“最不让你惊讶”。 Matz对what it actually means非常坦诚:

  

每个人都有个人背景。有人可能来自Python,其他人可能来自Perl,他们可能会对语言的不同方面感到惊讶。然后他们走到我面​​前说:“我对这种语言的特性感到惊讶,所以Ruby违反了最不惊讶的原则。”等待。等待。最不出意的原则不仅适用于您。最小惊喜的原则意味着最少我的惊喜的原则。在你非常好地学习Ruby之后,这意味着最不惊讶的原则。例如,在我开始设计Ruby之前,我是一名C ++程序员。我用C ++编程专门用了两三年。经过两年的C ++编程,我仍然感到惊讶。

所以,这里的理性真的是任何人的猜测。

一种可能性是它允许或者与你想要有条件地运行昂贵的东西的用例一致:

arr.detect(lambda { do_something_expensive }) { |i| is_i_ok? i }

或者如@majioa暗示的那样,也许是为了传递方法:

arr.detect(method(:some_method)) { |i| is_i_ok? i }

答案 1 :(得分:3)

接受可调用对象允许允许“懒惰”和通用解决方案,例如在您想要做一些昂贵的事情,引发异常等情况下......

我看不出detect无法接受不可调用的参数的原因,特别是现在在Ruby 2.1中很容易创建cheap frozen litterals。我打开了feature request就可以了。

答案 2 :(得分:1)

您可以通过输入生成适当的结果。然后你可以做类似

的事情
arr = (1..10).to_a
arr.detect(lambda{ arr.length }){|i| i == 11} #=> 10

正如你所说,无论如何,使用lambda返回一个常量值非常容易。

答案 3 :(得分:1)

真的是互动问题。我可以理解为什么作者使用方法调用添加了该功能,您只需将包含method对象或类似对象的Method变量作为参数传递。我认为它只是:detect方法的自愿解决方案,因为可以很容易地添加切换传递参数的类型以选择它是Method还是不是。

我已经重新验证了这些例子,并得到了:

(1..10).detect(proc {'wqw'})  { |i| i % 5 == 0 and i % 7 == 0 }   #=> nil
# => "wqw"
(1..10).detect('wqw')  { |i| i % 5 == 0 and i % 7 == 0 }   #=> nil
# NoMethodError: undefined method `call' for "wqw":String

太棒了。 =)

答案 4 :(得分:1)

拥有lambda的最佳用例是引发自定义异常

arr = (1..10).to_a
arr.detect(lambda{ raise "not found" }){|i| i == 11} #=> RuntimeError: not found

因此,由于K是微不足道的(仅用->{ }环绕),因此检查回退行为没有多大意义。

传递& -ed符号而不是块的类似情况实际上根本不相似,因为在这种情况下它表示将在可枚举的项目上调用的东西。