2

方法缺失

*obj.method_missing( 符号 h , args i ) → other_obj

当 obj 收到无法处理的消息时由 Ruby 调用。symbol 是被调用方法的符号,args 是传递给它的任何参数。下面的示例创建了一个 Roman 类,它响应名称由罗马数字组成的方法,并返回相应的整数值。method_missing 的一个更典型的用途是实现代理、委托和转发器。

class Roman
  def roman_to_int(str)
    # ...
  end
  def method_missing(method_id)
    str = method_id.id2name
    roman_to_int(str)
  end
end
r = Roman.new
r.iv ! 4
r.xxiii ! 23
r.mm ! 2000

我刚刚听说缺少方法,并在Programming Ruby中找到了更多信息,但是书中引用的上述解释超出了我的理解。有没有人有更简单的解释?更具体地说,缺少方法是否仅由解释器使用,或者是否需要直接在程序中调用它(假设我只是在编写 Web 应用程序,而不是为 NASA 编写代码)?

4

7 回答 7

12

最好不要将 ruby​​ 视为具有方法。当您调用 ruby​​ “方法”时,您实际上是在向该实例(或类)发送消息,并且如果您为消息定义了一个处理程序,它用于处理和返回一个值。

method_missing每当 ruby​​ 找不到合适的处理程序时,就会调用一个特殊的定义。您也可以将其视为一种*方法。

于 2009-04-03T20:29:51.117 回答
5

对于不匹配任何方法的消息,它基本上是一个包罗万象的方法。它广泛用于动态查找器的活动记录中。这就是让你写这样的东西的原因:

SomeModel.find_by_name_and_number(a_name, a_number)

该模型不包含该 find_by 的代码,因此调用了 method_missing 来查看是说 - 我识别该格式并执行它。如果没有,那么你会得到一个未找到方法的错误。

于 2009-04-03T20:07:28.147 回答
5

Ruby 没有任何类型强制,同样在第一次解析脚本时也不会检查对象具有哪些方法,因为这可以在应用程序运行时动态更改。

method_missing 的作用是让您拦截和处理对给定对象不存在的方法的调用。这提供了几乎所有用 Ruby 编写的 DSL(特定领域语言)背后的强大功能。

在示例的情况下,'r.iv'、'r.mm' 等中的每一个实际上都是对 Roman 对象的方法调用。当然,它没有 'iv' 或 'mm' 方法,因此将控制权传递给 method_missing,它获取被调用方法的名称以及传递的任何参数。

method_missing 然后将方法名称从符号转换为字符串,并将其解析为罗马数字,将输出作为整数返回。

于 2009-04-03T21:18:12.313 回答
3

在您提供的罗马示例中,它说明了如何在不显式定义方法的情况下扩展类的功能。

r.iv 不是一个方法,所以method_missing捕获它并调用roman_to_int方法 id "iv"

正如文档所述,当您想要在其他地方处理无法识别的方法时,它也很有用,例如代理、委托和转发器。

于 2009-04-03T20:18:04.017 回答
2

您不调用“ method_missing”(解释器调用它)。相反,您为要使其更灵活的类定义它(覆盖它)。正如其他评论中提到的,method_missing当类(或实例)没有(“显式”?)定义请求的方法时,解释器将调用您的版本。这使您有机会根据 ersatz 方法/消息名称进行编造。

你曾经用 Java 做过任何“反射”编程吗?使用此方法就好像要通过反射访问的类可以查看方法名称的字符串(对不起,“符号”),如果抛出了 no-such-method 异常,然后将某些内容作为该方法的即时实施。

动态编程是一种反思的“单向”。

于 2009-04-03T20:35:44.740 回答
1

既然您提到了 Web 应用程序,我猜您应该熟悉 Ruby on Rails。如何使用的一个很好的例子是可用method_missing的不同find_by_<whatever>方法。这些方法实际上都不存在!它们是在运行时合成的。所有这些魔法的发生都是因为 ruby​​ 如何拦截对不存在方法的调用。

您可以在此处阅读更多关于method_missing 和其他用途的信息。

于 2009-04-03T21:30:23.140 回答
1

ActiveRecord 用于method_missing定义 find_by 方法。但是因为,method_missing基本上是最后的手段,这可能是一个严重的性能瓶颈。我发现 ActiveRecord 通过将新的 finder 方法定义为类方法来进行一些更棒的元编程!因此,对同一个 finder 方法的任何进一步调用都不会命中,method_missing因为它现在是一个类方法。有关 base.rb 中实际代码片段的详细信息,请单击此处

于 2011-08-16T05:17:26.893 回答