0

在“rubymonk”和其他一些 ruby​​ 资源中,提到当您在对象上定义单例方法时,Ruby 正在将这个新方法添加到对象的元类中。对?还有一个访问元类的技巧,就是这样:

class Object
  def metaclass
    class << self
      self
    end
  end
end

foo = "I'm a string object"

def foo.shout
  puts self.upcase
end

foo.shout

p foo.metaclass.class
p foo.class.instance_methods.include? :shout
p foo.metaclass.instance_methods.include? :shout

正如我们所料,结果是:

I'M A STRING OBJECT
Class
false
true

一切都很好。但是如果我们将元类方法更改为 returnHash而不是self呢?

  class Object
      def metaclass
        class << self
          Hash
        end
      end
    end

然后我们检查这些事情:

p foo.class.instance_methods.include? :shout
p foo.metaclass.instance_methods.include? :shout
p String.instance_methods.include? :shout
p Object.instance_methods.include? :shout
p Hash.instance_methods.include? :shout

是的,所有这些都是错误的:

false
false
false
false
false

问题是,shout方法现在属于什么?它不是元类。那是什么?!

4

3 回答 3

1

仍然是元类,您刚刚删除了直接访问它的能力......

foo.instance_eval { class << self; self; end.instance_methods.include?(:shout) }
  => true
于 2014-03-24T18:02:16.810 回答
1

shout仍然属于元类,您甚至还没有失去访问元类的能力(正如其他答案所暗示的那样)。您刚刚在Object被调用上创建了一个无用的方法metaclass。这不会阻止您执行以下操作:

 (class << any_object_here; self; end)

请注意,class << ...语法是核心 Ruby 语法,不能仅通过重新定义方法来“更改”。

于 2014-03-24T18:10:28.647 回答
0

shout方法仍然属于foo的元类,您只是无法访问它,因为您选择始终Hash从您的方法返回。的方法定义foo.shout不受metaclass方法语义的影响。

于 2014-03-24T18:02:52.823 回答