Ruby 中 lambda 和 -> 运算符的区别

Difference between lambda and -> operator in Ruby

以下两个范围生成相同的结果,哪种语法更可取,还有其他区别吗?

scope :paid, lambda { |state| where(state: state) }

scope :paid, ->(state) { where(state: state) }

出于可读性原因,最好对单行块使用新语法 ->(在 Ruby 1.9 中引入),对多行块使用 lambda。示例:

# single-line
l = ->(a, b) { a + b }
l.call(1, 2)

# multi-line
l = lambda do |a, b|
  tmp = a * 3
  tmp * b / 2
end
l.call(1, 2)

这似乎是 bbatsov/ruby-style-guide 中建立的社区公约。

所以,在你的情况下,会更好:

scope :paid, ->(state) { where(state: state) }

没有区别,都是returns同一个Proc对象:

irb(main):033:0> lambda {|x| x*x}
=> #<Proc:0x007ff525b55b90@(irb):33 (lambda)>
irb(main):034:0> ->(x) {x*x}
=> #<Proc:0x007ff525b7e068@(irb):34 (lambda)>

在我看来,-> 更具可读性。

-> 是文字语法,如 "。其含义由语言规范确定。

Kernel#lambda 是一种与任何其他方法一样的方法。它可以被覆盖、删除、覆盖、monkeypatched、拦截,...

因此,从语义上讲,它们非常不同。

也有可能是他们的表现不一样。 Kernel#lambda 至少 有方法调用的开销。执行引擎实际上无法知道 Kernel#lambda 在运行时做了什么(因为它可以被猴子补丁)也将排除任何静态优化,尽管我不相信任何现有的 Ruby 执行引擎静态优化 lambda任何有意义的文字。

市场答案是正确答案。不过,有一个快速补充——如果需要将多行 lambda 作为参数,则有 2 种方法可以使用。例如在模型中创建一个范围,你可能需要考虑这个:

class User < ApplicationRecord
  # Bad - this will error because we are passing a block as an argument in
  # a method without parenthesis
  scope cool_users lambda do |arg|
    # some long query
  end

  # OK - when parenthesis are added, the lambda block will work 
  # without error (and passes rubocop). However, using parenthesis 
  # around a lambda block looks weird IMO
  scope(cool_users lambda do |arg|
    # some long query
  end)

  # Good - replacing do / end with {} functions without error, passes 
  # rubocop and looks good IMO
  scope cool_users lambda { |arg|
    # some long query
  }
end