【问题标题】:Better alternative to try method更好的替代尝试方法
【发布时间】:2019-03-01 16:55:23
【问题描述】:

我想要一段干净的代码,但我觉得这感觉很笨重。

有没有更好的方法来做到这一点?

User.try(:profile).try(:settings).try(:card).try(:options)

如果我消除 try 方法,我会得到一个 nil 方法错误。

是否还有另一段代码可以执行以下操作:

User.try(:profile,:settings, :card, :options)

【问题讨论】:

  • 顺便说一句,User.try(:profile,:settings, :card, :options) 不起作用的原因是您可以使用 try 提供方法参数和块。上面的代码尝试做User.profile(:settings, :card, :options)

标签: ruby-on-rails ruby activesupport


【解决方案1】:

从 ruby​​ 2.3.0 开始,您可以使用 &. 方法而不是 try

User&.profile&.settings&.card&.options

但是你应该避免这样的事情。

当您向可能返回nil 的对象发送消息时,或者当对象没有响应该消息时,您应该自行解决这个问题。使用try 只会加剧问题,就像nil-checking 一样。 编写行为一致的一致接口。

【讨论】:

  • 如果 User 是一个未初始化的常量,它会引发 NameError 错误,因此,安全导航运算符将无法按预期工作。
  • @SebastianPalma 在尝试profile 方法之前会引发关于未初始化常量的错误。
  • 顺便说一句 try 和安全导航 &. 并不完全等同 Spec
  • ^ a&.b = a.nil? ? nil : a.ba.try(:b) = a.respond_to?(:b) ? a.b : nil
【解决方案2】:

如果您使用的 Ruby 版本高于 2.3,则可以改用安全运算符。例如,

User.profile&.settings&.card&.options

这不是很整洁吗?

【讨论】:

    【解决方案3】:

    只是为了好玩

    自己动手:

    # concerns/deep_try.rb
    
    module DeepTry
      def deep_try(*methods)
        methods.reduce(self) { |receiver, method| receiver.try(method) }
      end
    end
    
    # user.rb (or anywhere else you want it)
    extend DeepTry
    

    这样您就可以安全地调用以下命令:

    User.deep_try(:profile, :settings, :card, :options)
    

    您也可以在实例级别上使用:

    @user.extend(DeepTry).deep_try(:profile, :settings, :card, :options)
    

    【讨论】:

    • tbh,我会省略 extend ActiveSupport::Concernclass_methods do。你可以在一个类中使用extend(而不是include)来做同样的事情。这也允许您将其应用于实例,而无需将其添加到类中。例如。 User.last.extend(DeepTry).deep_try(:profile, :settings, :card, :options)
    • 非常感谢@3limin4t0r - 很棒的指导。我已经更新了答案以反映这一点。
    【解决方案4】:

    我知道这在左领域,但你知道,思维的多样性。

    我创建了(非常小的)漫不经心的 gem,它允许在担心错误的情况下执行代码。使用这个 gem,代码看起来像:

    insouciant(nil) { User.profile.settings.card.options }
    

    捕获所有标准错误,而不仅仅是 nil 方法错误,还有一点额外的“好处”。出错时返回 nil 值。如果在您的应用程序中更有意义,您可以将其替换为其他值。

    完全省略参数会将错误消息作为字符串返回。

    【讨论】:

      猜你喜欢
      • 2018-10-09
      • 1970-01-01
      • 1970-01-01
      • 2017-11-19
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      相关资源
      最近更新 更多