7

我了解常规方法查找路径,即class, superclass/module, all the way up to BasicObject. 我认为对于单例版本的链也是如此,但当您在元链中混合模块时似乎并非如此。如果有人能解释为什么在我将这个模块包含在 Vehicle 的 eigenclass 中时,为什么在下面的示例中调用Automobile模块的banner方法而不是它的单例版本,我将不胜感激。

module Automobile
  def banner
    "I am a regular method of Automobile"
  end

  class << self
    def banner
      "I am a class method of Automobile"
    end
  end
end

class Vehicle 
  def banner
    "I am an instance method of Vehicle"
  end

  class << self
    include Automobile
    def banner
      puts "I am a class method of Vehicle"
      super
    end
  end
end

class Car < Vehicle
  def banner
    "I am an instance method of Car"
  end

  class << self
    def banner
      puts "I am a class method of Car"
      super
    end
  end
end

puts Car.banner

# I am a class method of Car
# I am a class method of Vehicle
# I am a regular method of Automobile
4

2 回答 2

8

首先,include不包括您可能期望的特征类方法。考虑:

module Foo
  class << self
    def do_something
      puts "Foo's eigenclass method does something"
    end
  end
end

module Bar
  include Foo
end

puts Bar.do_something
# undefined method `do_something' for Bar:Module (NoMethodError)

请注意,这与经典定义的类方法的行为一致:

module Foo
  def self.do_something
    puts "Foo's class method does something"
  end
end

module Bar
  include Foo
end

puts Bar.do_something
# undefined method `do_something' for Bar:Module (NoMethodError)

一个常见的习惯用法是在子模块中定义类方法,然后在包含模块时触发调用extend

module Foo
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def do_something
      puts "Foo::ClassMethod's instance method does something"
    end
  end
end

module Bar
  include Foo
end

puts Bar.do_something
# Foo::ClassMethod's instance method does something

要注意的第二件事是,您实际上将 的实例方法包含Automobile到 的特征类中Vehicle,因此将 的实例方法Automobile转换为 的(特征)类方法Vehicle

你的Car课基本上与这一切无关。这里唯一要注意的是,类继承也使类方法可用,而include不能。例子:

class Foo
  def self.do_something
    puts "Foo's class method does something"
  end
end

class Bar < Foo
end

puts Bar.do_something
# "Foo's class method does something"
于 2012-11-07T13:15:40.817 回答
2

首先,类是一个对象,就像其他对象一样,它也有自己的超类;其次,Eigenclass 本身是一个普通的类,只有匿名且有点不可见;第三,派生类的eigenclass的超类是基类的eigenclass;第四,include包含被包含模块的实例方法(不是单例方法),使它们成为接收者类对象的实例方法。

您的示例中有两个并行继承链

汽车 < 车辆 < ...

汽车的特征类 < 车辆的特征类 < 汽车 < ...

对 irb 进行以下测试:

class Object
  def eigenclass
    class << self
      self
    end
  end
end

Car.ancestors # => [Car, Vehicle, Object, Kernel, BasicObject]
Car.eigenclass.ancestors # => [Automobile, Class, Module, Object, Kernel, BasicObject]
Vehicle.eigenclass.ancestors # => [Automobile, Class, Module, Object, Kernel, BasicObject]
Car.eigenclass.superclass.equal? Vehicle.eigenclass # => true

你看,Automobile是在 eigenclass 继承链中。但遗憾的是,该ancestor方法没有返回不可见的特征类,尽管它们实际上在第二个链中。

于 2012-11-07T14:18:16.187 回答