0

编辑:让我稍微扩展一下我的意图:

鉴于 ruby​​ 对象从其类的实例方法中获取其方法。

我试图“证明”的是,通过向该对象的类添加实例方法,它们将成为该对象本身的方法。

所以:

class Test;end
Test.class.class_eval do 
  def foo
    puts "I am a method in #{self}"
  end
end
Test.foo
=> I am a method in Test
Test.class.foo
=> I am a method in Class

我实际上已经弄清楚为什么会发生这种情况。那是因为 Class.class 是......类!由于 Class 将 foo 作为其实例方法表的一部分,并且由于 Class.class 指向自身,因此它也将 foo 作为可调用的实例方法。

原帖如下:

只是为了更多地了解 Ruby 对象模型,我一直在做一些实验,以下行为让我感到惊讶:

假设我们有一个类测试:

class Test;end

然后,我们 class_eval Test.class 以便为 Test 对象添加一个方法:

Test.class.class_eval do
  def foo 
    puts 'foo called!'
  end
end

(相当于调用 Test.class.send(:define_method,:foo) ... )

然后:

irb(main):076:0> Test.foo
=> foo called!

但是将 foo 发送到班级也可以:

irb(main):006:0> Test.class.foo
=> foo called!

不过,我仍然不知道为什么。类的单例类不包含它(我想到的唯一可能的解释是,该方法以某种方式添加到类的单例类中):

Test.class.singleton_methods
=> [:nesting, :constants]

在这种情况下,方法查找如何工作?为什么发送 :foo 到 Test.class 也会调用该方法?我错过了什么吗?


作为参考,我对 Test 的实例做了同样的事情:

irb(main):001:0> class Test;end
=> nil
irb(main):002:0> _foo = Test.new
=> #<Test:0x007fa2c39e2f38>
irb(main):003:0> _foo.class.class_eval do
irb(main):004:1*   def foo
irb(main):005:2>    puts 'foo called!'
irb(main):006:2>   end
irb(main):007:1> end
=> :foo
irb(main):008:0> _foo.foo
foo called!
=> nil
irb(main):009:0> _foo.class.foo
NoMethodError: undefined method `foo' for Test:Class

这按我预期的方式工作。

提前致谢!

4

3 回答 3

2

当您调用Test.class它时,它返回的类Test 不是实际的 Test 类。

irb(main):001:0> class Test;end
=> nil
irb(main):002:0> Test.class
=> Class

当您调用时,_foo = Test.new您正在获取该类的一个实例,然后当您调用_foo.class它时,它会返回该实例的fooTest

在您的第一个示例中,您foo 添加到超类,而不是Test类。

要对此进行更多扩展,您应该做的是召集class_eval班级Test。最重要的是,您想要的是类方法,而不是实例方法。因为Test该类实际上是 的一个实例Class,所以您实际上在Class该类中定义了一个实例方法,而不是在Test. 你应该做的是:

Test.class_eval do
  def self.foo
    puts "foo called!" 
  end
end
于 2014-01-29T04:59:25.447 回答
1

你把事情搞混了一点。

  • Test.class_evalTest的特征类(即Test.)上执行
  • Test.class.class_evalTest'eigenclass' eigenclass 上执行(显然是Class.)
  • Test.class.singleton_methods返回Class'​​ eigenclass.

Test.class.class_eval实际上执行代码Class(在您的情况下声明Class' 实例方法。)

Test.foo被称为无问题,因为您已声明#fooonClass并且Test是它的一个实例(以及Test.class.)

于 2014-01-29T05:02:46.380 回答
0

长话短说,将 foo 发送到 Test.class 有效,因为:

Test.class == Class and Class.class == Class

Class.class 指向它自己。

于 2014-01-29T17:45:41.643 回答