【问题标题】:Do something if value is present如果存在价值,则做某事
【发布时间】:2015-09-02 15:17:51
【问题描述】:

我经常发现自己编写 Ruby 代码时,我会检查一个值是否存在,然后在该值存在时对它做一些事情。例如

if some_object.some_attribute.present?
  call_something(some_object.some_attribute)
end

如果可以写成这样的话我觉得会很酷

some_object.some_attribute.presence { |val| call_something(val) }
=> the return value of call_something

有人知道 Ruby 中是否有这样的功能,或者通过 activesupport 知道吗?

我为此功能打开了pull request

【问题讨论】:

  • 如果您只是在寻找单行,您可以使用内联 if 语句:call_something(some_object.some_attribute) if some_object.some_attribute.present?
  • 这会调用some_attribute 两次,出于冗长和性能的原因,这是不可取的(如果some_attribute 调用了IO)
  • attr = if some_object.some_attribute.present? call_something(attr) end 这只会调用一次属性
  • 不必说“更新”。如有必要,我们可以判断您是否修改了问题。相反,只需将您的附加信息添加到问题的正常流程中即可。
  • 你也可以写some_object.some_attribute.present & call_something(some_object.some_attribute)

标签: ruby-on-rails ruby activesupport


【解决方案1】:

您可以使用presencetry 的组合:

如果try 不带参数被调用,它会将接收者交给给定的块,除非它是nil

'foo'.presence.try(&:upcase)
#=> "FOO"

' '.presence.try(&:upcase)
#=> nil

nil.presence.try(&:upcase)
#=> nil

【讨论】:

  • 出于各种原因我不喜欢try,但这里是对这个问题的一个很好的回答。
  • 很好,但前提是你在轨道上
  • 真的很酷 - 而且您似乎可以省略 presence 并直接调用 try
  • @nsave, try 可通过拉入适当的 Active Support 核心库来使用,使其非常轻量级并且在非 Rails 代码中易于访问。见guides.rubyonrails.org/active_support_core_extensions.html#try
  • @NielsB。并非如此,在我的第二个示例中,' '.try(&:upcase) 将执行块并返回其结果,而 ' '.presence.try(&:upcase) 不会。
【解决方案2】:

你可以试试

do_thing(object.attribute) if object.attribute

这通常没问题,除非属性是布尔值。在这种情况下,如果值为 false,它将不会调用。

如果您的属性可能为假,请改用.nil?

do_thing(object.attribute) unless object.attribute.nil?

【讨论】:

  • 我知道,但我想避免提及some_object.some_attribute 两次。
  • 除非该属性实际上是一个正在做一些繁重工作的方法,否则调用它两次的开销很小,它是一条已经存储在内存中的数据,因此执行起来很快.
  • 您可以将其设置为局部变量,尽管这对于仅两种用法确实没有多大帮助。或者,您可以在 call_something 方法中添加 nil 检查,使调用代码更简洁。例如def call_something(attr); return if attr.nil? ; #main body; end
【解决方案3】:

虽然没有开箱即用的此类功能,但可以这样做:

some_object.some_attribute.tap do |attr|
  attr.present? && call_smth(attr) 
end

另一方面,Rails 提供了许多猴子补丁,以至于可以将一个附加到这个马戏团:

class Object
  def presense_with_rails
    raise 'Block required' unless block_given?
    yield self if self.present? # requires rails
  end
  def presense_without_rails
    raise 'Block required' unless block_given?
    skip = case self
           when NilClass, FalseClass then true
           when String, Array then empty?
           else false
           end
    yield self unless skip
  end
end

【讨论】:

  • 为什么不改用guides.rubyonrails.org/active_support_core_extensions.html#try。它是轻量级的,经过良好测试和支持。几年前,他们将 Active Support 分成小块,这样我们就可以挑选出我们想要的东西,并且可以依靠 AS 维护者来保持它的工作。
  • @theTinMan try 是一个不错的选择,我只是展示了一种可以使用的技术。顺便说一句,我赞成 Stefan 的回答。
猜你喜欢
  • 2011-08-16
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-13
  • 2015-05-06
  • 2018-12-09
相关资源
最近更新 更多