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
以下两个范围生成相同的结果,哪种语法更可取,还有其他区别吗?
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