【问题标题】:Call method only if it exists仅在存在时调用方法
【发布时间】:2021-01-22 17:12:51
【问题描述】:

是否有一些隐藏的 Ruby/Rails-magic 仅在方法存在时才调用它?

假设我想打电话

resource.phone_number

但我事先不知道资源是否响应phone_number。一种方法是

resource.phone_number if resource.respond_to? :phone_number

如果用在错误的地方,那就不是那么漂亮了。我很好奇是否存在更符合try 使用方式的东西(resource.try(:phone_number))。

【问题讨论】:

  • 作为一个极端的例子,我建议在这种情况下覆盖Objectmethod_missing 以返回nil。这是调试的恐怖。有些人会认为它是糟糕的风格、元数据和不必要的。
  • @User bah,一点也不可怕。您只需将堆栈重新返回到抛出 nil 异常的位置:-)
  • 使用respond_to 是最好的选择
  • 随意添加它作为单独的答案,我会给你一个接受。
  • @Frans 你介意接受投票最多的答案,这样我就可以删除我不正确的答案吗?

标签: ruby-on-rails ruby


【解决方案1】:

如果您对标准的 ruby​​ 语法不满意,您可以:

class Object
  def try_outside_rails(meth, *args, &cb)
    self.send(meth.to_sym, *args, &cb) if self.respond_to?(meth.to_sym)
  end
end

现在:

resource.try_outside_rails(:phone_number)

会按照你的意愿行事。

【讨论】:

  • 你正在覆盖 Rails 中现有的 try 方法
  • Ruby 非常棒。这不足以让我需要为它定义一个我自己的方法,我只是想知道它是否已经存在一个方法。
  • @apneadiving 谁谈到了Rails
  • 问题标记为ruby-on-rails
  • respond_to? 仅在挑战公共成员时产生 true,受保护和私有成员将产生 false,但它们仍然可以通过 instance.send(:method, args) 访问
【解决方案2】:

我会尝试defined? (http://ruby-doc.org/docs/keywords/1.9/Object.html#defined-3F-method)。它似乎完全符合您的要求:

resource.phone_number if defined? resource.phone_number

【讨论】:

  • 这不起作用,因为resource.phone_number 是一个有效的表达式。如果resource 在范围内,它将始终返回true。
【解决方案3】:

我知道这是很老的帖子。但只是想知道这是否是一个可能的答案以及影响是否相同。

resource.try(:phone_number) rescue nil

谢谢

【讨论】:

  • 有了 Rails 4,你甚至不需要 rescue: api.rubyonrails.org/classes/Object.html#method-i-try
  • 'try' 方法不是要检查一个方法是否存在,而是要保护你免受 nil 的影响。例如。 nil.try(:some_method) 将返回 nil 而不是引发异常,但 valid_reference.try(:non_existant_method) 仍然会失败(除非你已经完成了添加 rescue nil)。
  • 在程序的正常流程中使用救援不是一个好习惯。抛出和捕获异常会增加程序的开销。
  • @Josh 我不认为开销是主要问题;在第一个问题中使用 Ruby 已经增加了大量开销。但是,它会扭曲控制流,使程序更难理解。异常应该用于例外情况,而不是标准控制流。所以,你是对的,但我认为你使用了错误的论点。 :)
  • 这太糟糕了,你不应该这样做。如果被调用的方法发生任何异常(甚至是语法错误),都会被捕获并忽略。
【解决方案4】:

我不能说效率,但是像......

Klass.methods.include?(:method_name) 

在 Rails 4 中为我工作

【讨论】:

  • 这应该适用于大多数情况(尽管Klass.method_defined? 更直接)。但是,一个潜在的问题是,可以专门为所选实例禁用任何方法(Module#undef_method 作为单例类)。所以,很可能你的方法不起作用。 This past answer 根据具体需求总结了最佳方案。
【解决方案5】:

如果定义了A.c 而没有定义A.aA.b,您可以执行A.a rescue A.b rescue A.c,它会像魅力一样工作。不过,你会违反一些愚蠢的规则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    相关资源
    最近更新 更多