Ruby 如何使用 define_method 定义 class method?

artone · 2013年01月07日 · 最后由 xiongmao86 回复于 2013年04月29日 · 6536 次阅读

我晓得可以用 define_singleton_method 这个方法,不过我想知道的是,以下这两种方法之间的差别:

class C; end

C.instance_eval do
  def method_a
    puts self.class
  end
end

C.method_a
# => Class

C.instance_eval do
  define_method("method_b") { puts self.class }
end

C.method_b
# => undefined method `method_b' for C:Class (NoMethodError)

我前后分别用了两种方式定义 C class 的 class method,这两种方式的差异是什么?为什么前者可以,后者不行呢?

C.new.method_b

OK,重新读一次文档了:Defines an instance method in the receiver.

define_method 永远只会建立 instance method,所以即使塞在 instance_eval 里也不会变成 class method,应该是这样理解吧。

这也是个办法:

class C
  def self.metaclass
    class << self
      self
    end
  end
end

C.class_eval do
  def method_a
    puts self
  end

  define_method(:method_b) { puts self }
end

C.new.method_a # => #<C:0x007fe70c886f30>
C.new.method_b # => #<C:0x007fe70c886eb8>

C.metaclass.instance_eval do
  define_method(:method_c) { puts self }
end

C.method_c # => C

不是有 define_singleton_method 吗?

engine_class = class << self; self; end engine_class.send(:define_method, callback) { |*args| code }

又是一个茴字有几种写法的问题,不过这就是 ruby 神奇的地方!

Metaprogramming ruby 有说过,define_method 的可以使用 block 外围的作用域,而 def 开启了一个新的局部作用域。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号