Ruby的方法解绑机制有什么意义?

时间:2015-11-14 12:10:21

标签: ruby methods metaprogramming

Method#unbind返回对该方法的UnboundMethod引用,该引用稍后可以使用UnboundMethod#bind绑定到另一个对象。

class Foo
  attr_reader :baz

  def initialize(baz)
    @baz = baz
  end
end

class Bar
  def initialize(baz)
    @baz = baz
  end
end

f = Foo.new(:test1)
g = Foo.new(:test2)
h = Bar.new(:test3)
f.method(:baz).unbind.bind(g).call # => :test2
f.method(:baz).unbind.bind(h).call # => TypeError: bind argument must be an instance of Foo

最初,我认为这非常棒,因为我预计它会与JavaScript的Function.prototype.call() / Function.prototype.apply()类似。但是,要绑定方法的对象必须属于同一类

我能想到的唯一一个应用程序是,如果解除绑定方法,丢失原始实现(重新定义原始或单例类中的方法),然后重新绑定并调用它。

2 个答案:

答案 0 :(得分:2)

我总结了迄今为止我发现的好用途。但是,它们都没有使用unbind

首先,使用旧的实现覆盖方法。 Source,感谢@WandMaker。

假设你想做这样的事情:

class Foo
  alias old_bar bar

  def bar
    old_bar
    some_additional_processing
  end
end

这会有效,但会留下old_bar,这不是理想的事情。相反,人们可以这样做:

class Foo
  old_bar = instance_method(:bar)

  define_method(:bar) do
    old_bar.bind(self).call
    some_additional_processing
  end
end

其次,从层次结构中调用方法的另一个实现。 Source

帖子中给出的非常实用的例子是,在调试过程中,您经常需要找到定义方法的位置。一般来说,您可以通过以下方式实现:

method(:foo).source_location

但是,如果当前实例实现了method方法,那将无法工作,就像ActionDispatch::Request的情况一样。在这种情况下,你可以这样做:

Kernel.instance_method(:method).bind(self).call(:foo).source_location

答案 1 :(得分:0)

Method和UnboundMethod类型期望绑定目标必须是引用该方法的原始类的子类。但是,方法实现了#to_proc方法,并且可以摆脱“相同类类型”约束。

您必须使用#send方法,因为#define_method是私有的(您无法直接调用它)。

class A
  def hoge ; "hoge" ; end
end

class B ; end

hoge = A.new.method(:hoge)

B.send(:define_method, :hoge_in_b, &hoge) #converting to proc

b = B.new
puts b.hoge_in_b