Как наследование работает в Ruby?
По словам Дэйва Томаса в своем выступлении о объектной модели Ruby, в Ruby нет "методов классов". Существует только различие между тем, является ли получатель метода "объектом класса" или "объектом экземпляра".
class Dave
def InstaceMethod ### will be stored in the current class (Dave)
puts "Hi"
end
class << self ### Creates an eigenclass, if not created before
def say_hello
puts "Hello"
end
end
end
По умолчанию, ancestors
Метод не показывает метакласс:
class Dave
class << self
def metaclass ### A way to show the hidden eigenclass
class << self; self; end
end
end
end
p Dave.ancestors
# => [Dave, Object, Kernel, BasicObject]
p Dave.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
Тем не менее, я предполагаю, что реальный будет что-то вроде:
# => [<eigenclass>, Class, Module, Object, Kernel, BasicObject]
p Dave.class.instance_method(false)
# => [:allocate, :new, :superclass]
p Dave.metaclass.instance_method(false)
# => [:say_hello, :metaclass]
Теперь о наследстве.
class B < Dave
end
p B.say_hello
# => "Hello"
p B.ancestors
# => [B, Dave, Object, Kernel, BasicObject]
p B.class.instance_methods(false)
# => [:allocate, :new, :superclass]
Следующее создаст новый собственный класс для B
:
p B.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
p B.metaclass.instance_method(false)
# => []
Как бы
B.ancestors
а такжеB.metaclass.ancestors
выглядеть, когда собственные классы тоже включены? Методsay_hello
хранится в собственном классе, (который я предполагаюB.class
наследует) но где это?Так как есть две цепочки предков (
B.ancestors
а такжеB.class.ancestors
или жеB.metaclass.ancestors
) как на самом деле происходит наследование?
3 ответа
Eigenclass является скрытым подлый. Вы успешно раскрыли это, открыв урок. Но его не существует у предков нормального класса. И поскольку он скрыт, вы не можете увидеть его, отправив ancestors
метод самого собственного класса. Дерево наследования выглядит следующим образом:
B ---S--> Dave ---S---> Object ---S---> BasicObject
| | | |
E E E E
| | | |
#B --S--> #Dave ---S---> #Object ---S---> #BasicObject --S---> Class,,Object,BasicObject
S
выступает за суперкласс, в то время как E
для собственного класса.
Объект (а также класс, который является объектом, экземпляром класса) имеет поле класса, которое указывает на его класс. Создание одноэлементного класса (eigenclass/metaclass) создает анонимный класс и изменяет этот указатель так, чтобы он указывал на анонимный класс, указатель класса которого будет указывать на исходный класс. class
Метод не отображает анонимный класс, только оригинальный класс. То же самое для миксинов. У класса есть поле суперкласса. Метод include
создает анонимный прокси, указатель суперкласса изменяется для указания на анонимный прокси-класс, а оттуда на суперкласс. Метод ancestors
не показывает анонимный класс, но имя включенного модуля. superclass
Метод не отображает анонимный прокси-класс, только оригинальный суперкласс.
Вы можете прочитать это: почему символы в Ruby не считаются типом переменной?
В комментарии к этому ответу есть ссылка на интересную статью о синглтон-классе, которую можно найти в блоге Devalot.
Нужно некоторое время, чтобы ассимилировать эти цепочки наследования. Поскольку хорошая картина заслуживает длинного объяснения, я рекомендую главу 24 "Метапрограммирование в кирке" http://pragprog.com/book/ruby3/programming-ruby-1-9 которой есть различные картинки обо всех этих цепочках.
По умолчанию метод предков не показывает метакласс:
и 1. Как бы выглядели B.ancestors ..., когда также включены собственные классы?
ancestors
касается цепочки суперкласса. Собственный класс не принадлежит цепочке суперкласса.
p Dave.metaclass.ancestors
=> [Класс, Модуль, Объект, Ядро, БазовыйОбъект]
Тем не менее, я предполагаю, что реальный будет что-то вроде:
=> ["собственный класс", класс, модуль, объект, ядро, базовый объект]
Правильный.
Вы можете упростить свой класс Дейва:
class Dave
def self.say_hello # another way to create an eigenclass, if not created before
puts "Hello"
end
def self.metaclass # A way to show the hidden eigenclass
class << self
self
end
end
end
Dave.say_hello # => Hello
Dave.new.class.say_hello # => Hello
p Dave.metaclass.instance_methods(false) # => [:say_hello, :metaclass]
p Dave.singleton_methods # => [:say_hello, :metaclass]
def self.metaclass
является лишним с Ruby 1.9.2, которая представила Object#singleton_class
,
Проверьте ниже ссылки даст вам обзор: