新手问题 eigenclass 和 Module 的问题

woody1983 · 2013年09月18日 · 最后由 piecehealth 回复于 2013年09月19日 · 3229 次阅读

元编程#129Pages#Quiz

例子弄错了~在线编辑器害死人 凸

module MyModule 
  def my_method; 'hello';end
end

class Myclass 
  include MyModule
end

irb(main):004:0> MyModule.my_method
#NoMethodError: undefined method `my_method' for MyModule:Module
irb(main):010:0> puts Myclass.my_method
#NoMethodError: undefined method `my_method' for Myclass:Class
irb(main):011:0> obj = Myclass.new
#=> #<Myclass:0x861fa78>
irb(main):012:0> puts obj.my_method
#hello
#=> nil

在 Module 中定义一个普通的实例方法 Myclass Include 该 Module 只有 Myclass 的实例 obj 可以调用 也就是说my_method一直作为实例方法在 ancestors 中流窜

module MyModule 
    def self.my_method; 'hello';end
end

class Myclass
  include MyModule
end

irb(main):007:0> MyModule.my_method
#=> "hello"
irb(main):008:0> Myclass.my_method
#NoMethodError: undefined method `my_method' for Myclass:Class
irb(main):009:0> obj = Myclass.new
#=> #<Myclass:0x8627980>
irb(main):010:0> obj.my_method
#NoMethodError: undefined method `my_method' for #<Myclass:0x8627980>

第二次 将 Module 中的方法改成是了实例方法 结果正常 只有 MyModule 可以正常调用 但 Myclass 并没有继承到 难道在 Myclass 的 eigenclass 中并没有得到这个继承?

module MyModule 
  def my_method; 'hello';end
end

class Myclass 
  class << self
    include MyModule
  end
end

irb(main):009:0> MyModule.my_method
#NoMethodError: undefined method `my_method' for MyModule:Module
irb(main):010:0> Myclass.my_method
#=> "hello"
irb(main):011:0> obj = Myclass.new
#=> #<Myclass:0x8627570>
irb(main):012:0> obj.my_method
#NoMethodError: undefined method `my_method' for #<Myclass:0x8627570>

第三次和第一次的修改差异在 将 MyModule 植入到 Myclass 的 eigenclass 中了~ Myclass 可以正常调用该类方法

可是作为 Myclass 的实例对象 obj 却不能调用这个 my_method 了

module MyModule 
    def self.my_method; 'hello';end
end

class Myclass 
  class << self
    include MyModule
  end
end

irb(main):009:0> MyModule.my_method
#=> "hello"
irb(main):010:0> Myclass.my_method
#NoMethodError: undefined method `my_method' for Myclass:Class
irb(main):011:0> obj = Myclass.new
#=> #<Myclass:0x862bfa8>
irb(main):012:0> puts obj.my_method
#NoMethodError: undefined method `my_method' for #<Myclass:0x862bfa8>

# my_method就算变成Module的类方法以后 还是被继承下来了 和普通的Include看起来效果好像是一样的

第四次和第二次 得到的结果是一样的 也就是进没进 Myclass 的 eigenclass 都一样~

我把第四部分重写了一下 加入了另一个实例方法在 Module 中

module MyModule
  def self.my_method; 'hello';end
  def mine_method; 'another method'; end
end

class Myclass
  class << self
    include MyModule
  end
end

irb(main):012:0* Myclass.mine_method
#=> "another method"
irb(main):013:0> Myclass.my_method
#NoMethodError: undefined method `my_method' for Myclass:Class

看来class << self这种方法只能把 MyModule 中的实例方法植入到 Myclass 的 eigenclass 中 类方法不行

难道下面这么做是让 MyModule 仅仅植入到 Myclass 的 eigenclass 中 而在 Myclass 中是不可见的?

class Myclass 
  class << self
    include MyModule
  end
end

如果你的 Myclass 不是指 Object 的话就可以给 ruby 提 bug 了

例子有问题。

#2 楼 @zgm 而且 Pages129 上的那段话

当类包含模块时,它获得的是该模块的实例方法,---而不是类方法。类方法存在于模块的eigenclass中,仍然无法触碰。

然后他下面解决的时候 就把

module MyModule
  def self.my_method; 'hello'; end
end

中的self 去掉了~ 这是在逗我吗?这样修改的话 下来的还是一个实例方法而已 Quiz 中的类方法还是没有下来。

#1 楼 @jjym 看样子应该不是 Bug 可能是我的理解有问题 Myclass 只是一个普通的 Class 但如果说 Class 也是一个 Object 的话 ...

Myclass.ancestors  # => [Myclass, MyModule, Object, Kernel]

例子有问题

#5 楼 @outman 看到了 我正在改 在 irb 试了一下 不是这个结果

#2 楼 @zgm 是我写的例子有问题~我修改了一下 现在就是第三步不是太明白

我按照 Bill 的方法把 MyModule Myclass 以及他们的 eigenclass 还有 obj 的五者之间的联系 画成了图 然后发现 Myclass 的 eigenclass 并不是从 MyModule 中获取的 my_method 而是直接从 MyModule 中获取的,可以交叉的?还是说 其实 module 这个东西是没有 eigenclass 的 MyModuleh & Myclass & Myclass.eigenclass 这三个对象之间其实是三角形关系?

#7 楼 @woody1983 我擦,你说的好乱。

  1. C include M => M 中的实例方法变成 C 的实例方法。
  2. C extend M => M 中的实例方法变成 C 的类方法。
  3. C 的 engenclass include M => M 中的实例方法变成 C 的 engenclass 的实例方法,同 1 道理相同,所以变成了 C 的类方法。
  4. C 的 engenclass extend M => M 中的实例方法变成 C 的 engenclass 的类方法,同 2 道理相同,但是一般没人会这么用。
  5. 这一切的一切和 M 的类方法没有半毛钱关系!!!

没什么奇怪的,对于 module 来说,include 本身和继承没任何关系,所谓 include 一个 module,最相似的用法就是 c++ 里面的 inline,c 里面的#define。简单说,就是在现场展开,相当于把代码在 include 的地方又当作字符串拷贝了一遍。

而 self 只是提供了个不同于 class 的访问层次结构而已,你可以看作是 class 内部的一个隔离区。

#8 楼 @zgm 那如果我要继承一个 M 的类方法的话 就只能把它变成实例方法并继承?

有不改变其 Module 类方法身份也能继承下来的方法吗?

#11 楼 @woody1983 你的意思是把一个 Model 的类方法变成一个类的实例方法吗?

#12 楼 @zgm #12 楼 @zgm 是的~ 否则我总觉得一个 Module 的类方法声明出来以后好像进入了隔离区~ 谁都不能继承

#10 楼 @rasefon 是蛮像隔离区的概念的~ 声明一个方法为 self 以后 不论是下一级的 class 还是其 eigenclass 都无法访问

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