Неожиданное поведение собственного класса Ruby


person bazaretas    schedule 03.06.2014    source источник


Ответы (3)


Из этого сообщения в блоге вы можете построить аналогичную диаграмму:

                        +------------------+               +-------------------+
                        |      Object      |- eigenclass ->| Object eigenclass |
                        +------------------+               +-------------------+
                                 ^                                   ^             
                                 | superclass             superclass |                                                     
                        +------------------+               +-------------------+
                        |        A         |- eigenclass ->|    A eigenclass   |
                        +------------------+               +-------------------+
                                 ^
                                 | superclass
+-------+               +------------------+                                   
| A.new |- eigenclass ->| A.new.eigenclass |                                   
+-------+               +------------------+    

Попытка найти суперкласс собственного класса экземпляра A показывает, что он указывает на класс A.

A.new.eigenclass.superclass      # => A                               

Class.new возвращает экземпляр объекта класса, то есть новый класс. Это класс, как и класс A.

Class.new.class # => Class
A.class         # => Class

Суперкласс A и суперкласс Class.new оба неявно равны Object.

Class.new.superclass # => Object
A.superclass         # => Object

Поскольку надклассом A является Object, надклассом собственного класса A является собственный класс Object.

Object.eigenclass                            # => #<Class:Object>
A.eigenclass.superclass                      # => #<Class:Object>
A.eigenclass.superclass == Object.eigenclass # => true

Точно так же нахождение суперкласса собственного класса Class.new дает собственный класс Object

Class.new.eigenclass.superclass              # => #<Class:Object>

Разница между Class.new и A.new заключается в том, что Class.new сам по себе является классом и поэтому может создавать новые объекты, а A.new не может.

Class.new.new # => #<#<Class:0x007f86b50d8f70>:0x007f86b50d8f20>
A.new.new     # => NoMethodError: undefined method `new' for #<A:0x007f86b50cbf50>
person hjing    schedule 04.06.2014
comment
Оба метода new совершенно разные. Class.new — это статический метод. В то время как A.new является методом экземпляра в классе Class. ruby-doc.org/core-2.0/Class.html# метод-c-новый - person bazaretas; 10.06.2014

С помощью puts A.new.eigenclass.superclass вы фактически вызываете #eigenclass для экземпляра класса A. Я начну с предыстории, чтобы объяснить, как на самом деле работает собственный класс, а затем перейду к рассказу о том, что происходит в вашем коде.

Предыстория:

EigenClass — это скрытый класс, который содержит одноэлементные методы, доступные только для этого конкретного объекта.

Итак, для obj = Foo.new иерархия классов на самом деле выглядит так:

obj --eigenclass--> #> --(суперкласс)--> A

вместо:

объект --(класс)--> А

Скрытый класс может быть создан после того, как вы захватили себя с помощью #eigenclass.

Теперь в Ruby Class является объектом. Это также означает, что #eigenclass также должен показывать скрытый собственный класс A (где хранятся сиглетонные методы A).

A --(собственный класс)--> # --(суперкласс)--> #

Теперь причина, по которой он показывает # вместо A, заключается в том, что Ruby организует классы, суперклассы и собственные классы в очень красивом шаблоне. Это можно показать на примере вместо того, чтобы цитировать его запутанными словами:

A.superclass #=> Object   
A.eigenclass #=> #<Class: A>   
A.eigenclass.superclass #=> #<Class: Object> => Eigenclass of Object   
A.eigenclass.superclass == Object.eigenclass #=> true   

Суперкласс собственного класса класса – это собственный класс суперкласса исходного класса.

Теперь, что касается вашего случая: Class.new.eigenclass.superclass, теперь это говорит само за себя. Class.new соответствует новому анонимному классу, скажем, B, и вы фактически вызываете для него eigenclass.superclass. Поскольку надклассом B является Object, надклассом собственного класса B является собственный класс надкласса B.

Старался изо всех сил объяснить на примерах. Пожалуйста, не стесняйтесь уточнять это в комментариях ниже; соответственно обновит ответ. Дополнительно (из Pragmatic MR): Снимок из Pragmatic MR.

На рисунке выше D наследуется от C. Таким образом, D.eigenclass.superclass является собственным классом (суперкласса D) [который является C]. Теперь суперклассом C является Object.. и такая же логика.

С Уважением

person kiddorails    schedule 04.06.2014
comment
Я думаю, вы имеете в виду A.eigenclass.superclass == Object.eigenclass - person bazaretas; 04.06.2014
comment
Да, прости. Непреднамеренно пропустил это. - person kiddorails; 04.06.2014
comment
Мне нравится, как вы расположили USB-кабель, чтобы он выглядел как человек-палка, любующийся вашим рисунком. +1 (за ответ, а не за человечка). - person Cary Swoveland; 04.06.2014

Собственный класс класса имеет целую теневую иерархию собственных классов для предков класса, которые все находятся между собственным классом и классом. Это связано с тем, что классы должны наследовать методы классов своих предков. Например, если вы сделали def Numeric.kind_of_number?() true end, вы ожидаете, что Fixnum.kind_of_number? будет правдой. Таким образом, вам нужно иметь собственный класс Numeric в качестве предка собственного класса Fixnum.

person Chuck    schedule 03.06.2014