【问题标题】:How are respond_to and respond_to_missing different?respond_to 和 respond_to_missing 有何不同?
【发布时间】:2014-01-10 22:36:00
【问题描述】:

我很困惑何时使用这些方法。 来自respond_to? 文档:

如果 obj 响应给定的方法,则返回 true。私有方法 仅当可选的第二个参数时才包含在搜索中 计算结果为真。

如果该方法没有实现,如 Windows 上的 Process.fork, GNU/Linux等上的file.lchmod,返回false。

如果方法没有定义,respond_to_missing?方法被调用并且 结果返回。

还有respond_to_missing?:

钩子方法返回obj是否可以响应id方法或 不是。

参见#respond_to?。

这两种方法都需要 2 个参数。
两种方法看起来是一样的(检查某个对象是否响应给定的方法)那么为什么我们应该同时使用(拥有)这两种方法?

定义 'resond_to_missing?` 让您能够采用方法:

class A
  def method_missing name, *args, &block
    if name == :meth1
      puts 'YES!'
    else
      raise NoMethodError
    end
  end

  def respond_to_missing? name, flag = true
    if name == :meth1
      true
    else
      false
    end
  end
end

[65] pry(main)> A.new.method :meth1
# => #<Method: A#meth1>

为什么respond_to? 不能这样做?

我猜的:

respond_to? 检查方法是否在:

  1. 当前对象。
  2. 父对象。
  3. 包含的模块。

respond_to_missing? 检查方法是否为:

  1. 通过method_missing定义:

通过可能的方法数组:

def method_missing name, *args, &block
  arr = [:a, :b, :c]
  if arr.include? name
    puts name
  else
    raise NoMethodError
  end
end

将其委托给不同的对象:

class A
  def initialize name
    @str = String name
  end

  def method_missing name, *args, &block
    @str.send name, *args, &block
  end
end

2 。其他我不知道的方式。

应该在哪里定义/使用(我也猜):

从 1.9.3 开始(我记得公平)只定义 respond_to_missing? 但只使用 respond_to?

最后的问题

我说的对吗?我错过了什么吗?纠正所有不好的地方和/或回答这个问题中提出的问题。

【问题讨论】:

标签: ruby metaprogramming


【解决方案1】:

respond_to_missing? 应该在您使用方法缺失技术提供其他方法时更新。这将使 Ruby 解释器更好地理解新方法的存在。

其实不使用respond_to_missing?,是无法获取使用method的方法的。

Marc-André posted a great article 关于respond_to_missing?

为了respond_to?要返回 true,可以对其进行专门化,如下所示:

class StereoPlayer
  # def method_missing ...
  #   ...
  # end

  def respond_to?(method, *)
    method.to_s =~ /play_(\w+)/ || super
  end
end
p.respond_to? :play_some_Beethoven # => true

这更好,但它仍然不能让 play_some_Beethoven 的行为完全像一个方法。确实:

p.method :play_some_Beethoven
# => NameError: undefined method `play_some_Beethoven'
#               for class `StereoPlayer'

Ruby 1.9.2 引入了respond_to_missing?,它为问题提供了一个干净的解决方案。而不是专攻respond_to?,而是专攻respond_to_missing?。这是一个完整的例子:

class StereoPlayer
  # def method_missing ...
  #   ...
  # end

  def respond_to_missing?(method, *)
    method =~ /play_(\w+)/ || super
  end
end

p = StereoPlayer.new
p.play_some_Beethoven # => "Here's some_Beethoven"
p.respond_to? :play_some_Beethoven # => true
m = p.method(:play_some_Beethoven) # => #<Method: StereoPlayer#play_some_Beethoven>
# m acts like any other method:
m.call # => "Here's some_Beethoven"
m == p.method(:play_some_Beethoven) # => true
m.name # => :play_some_Beethoven
StereoPlayer.send :define_method, :ludwig, m
p.ludwig # => "Here's some_Beethoven"

另见Always Define respond_to_missing? When Overriding method_missing

【讨论】:

    猜你喜欢
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 2016-12-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-16
    • 2011-04-02
    • 1970-01-01
    相关资源
    最近更新 更多