wiele z tych wyjaśnień jest oparta na How Ruby Method Dispatch Works James Coglan, trochę z Ruby Hacking Guide, a tylko smidge z source.
Aby rozpocząć z Podsumowując, pochodzenie wygląda następująco:
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
---> Parent
~~~> Singleton class
Zacznijmy od początku i zbudować. BasicObject
jest źródłem wszystkiego - jeśli sprawdzisz BasicObject.superclass
, otrzymasz nil
. BasicObject
jest również instancją Class
. Tak, to jest okrągłe, i jest special case in the code, aby sobie z tym poradzić.Kiedy A
jest instancją B
, A.singleton_class
jest dzieckiem B
, więc mamy to:
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Object
dziedziczy z BasicObject
. Gdy A
dziedziczy po B
, A
jest dzieckiem o numerach i , które jest potomkiem B.singleton_class
. Object
zawiera także Kernel
. Kiedy A
zawiera B
, B
jest wstawiany jako pierwszy przodek A
(po A
sam w sobie, ale przed A.superclass
).
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
Kernel
jest wystąpienie Module
. Jest to jedyny przypadek Module
, którego zobaczymy, a jego klasa singletona nie pojawia się w żadnym łańcuchu przodków, więc nie wyjdę poza to.
Teraz przejdziemy do Foo
, która dziedziczy po Object
(chociaż nie trzeba pisać < Object
). Możemy już dowiedzieć się, co to jest Foo
i jego klasa singleton.
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
Teraz Class
dziedziczy z Module
i Module
dziedziczy z Object
, więc dodać Module
i odpowiednie klasy Singleton. Ponieważ Module < Object
i Object < BasicObject
i BasicObject.instance_of?(Class)
jest to miejsce, w którym rysunek staje się nieco funky. Pamiętaj, że po prostu przestajesz przechodzić w górę za każdym razem, gdy trafisz na BasicObject
.
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ |
| | |
| BasicObject ~~~~~> #<Class:BasicObject> |
| ^ ^ |
| | Kernel | |
| | ^ | |
| | | | +----------------------------------------+
| +-----+----+ | |
| | | v
+-------> Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
Ostatni krok. Każde wystąpienie Class
ma singleton_class
(choć nie będzie instancji, dopóki nie jest potrzebne, lub potrzebujesz więcej RAM). Wszystkie nasze klasy singleton są instancjami Class
, więc mają klasy singleton. Uważaj na to zdanie: rodzic klasy singleton jest rodzicem klasy singleton klasy. Nie wiem, czy istnieje zwięzły sposób na stwierdzenie, że jeśli chodzi o systemy typu, a Ruby source mówi, że po prostu robi to dla spójności w każdym przypadku. Tak więc, jeśli poprosisz o Foo.singleton_class.singleton_class
, język szczęśliwie obliguje cię i propaguje niezbędne rodziców w górę, prowadząc ostatecznie do:
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
Jeśli zaczniesz z dowolnego węzła na tym wykresie i przesuw głębokości pierwszego, od prawej do lewej (i zatrzymaj się na BasicObject
, otrzymasz łańcuch przodków węzła, dokładnie tak, jak chcieliśmy, i stworzyliśmy go z pewnych podstawowych aksjomatów, więc możemy po prostu móc mu zaufać, ponieważ brakuje zaufania, istnieje kilka interesujących sposobów, aby zweryfikuj strukturę dalej:
Spróbuj spojrzeć na node.singleton_class.ancestors - node.ancestors
dla dowolnego węzła grafu, co daje nam przodków klasy singleton, którzy nie są przodkami sam węzeł, który eliminuje niektóre z mylących nadmiarowości na liście.
> Foo.singleton_class.singleton_class.ancestors - Foo.singleton_class.ancestors
=> [#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>,
#<Class:Class>, #<Class:Module>]
Możesz również zweryfikować jednego z rodziców z node.superclass
.
> Foo.singleton_class.singleton_class.superclass
=> #<Class:#<Class:Object>>
I można nawet sprawdzić, czy obiekt jest tożsamość wszystko spójne, więc nie są anonimowe klas pojawiały się w każdym miejscu, bez określonego stosunku do siebie.
> def ancestor_ids(ancestors)
> ancestors.map(&:object_id).zip(ancestors).map{|pair| pair.join("\t")}
> end
> puts ancestor_ids(Foo.ancestors)
70165241815140 Foo
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.ancestors)
70165241815120 #<Class:Foo>
70165216039400 #<Class:Object>
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object # Same as Foo from here down
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.singleton_class.ancestors)
70165241980080 #<Class:#<Class:Foo>>
70165215986060 #<Class:#<Class:Object>>
70165215986040 #<Class:#<Class:BasicObject>>
70165216039440 #<Class:Class>
70165216039420 #<Class:Module>
70165216039400 #<Class:Object> # Same as Foo.singleton_class from here down
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
A to, w dużym skrócie, to jak Ty snipe a nerd.
Zakładasz, że jest w ogóle zorganizowana. Jesteś pewien, że to jest/powinno być zorganizowane? –
Być może mógłbyś wyjaśnić swoje pytanie? Czy pytasz, gdzie jest zdefiniowana metoda paska w twoim drugim przykładzie? – saghaulor
Metoda paska jest zdefiniowana. Pytam, jak zorganizowana jest hierarchia dziedziczenia w drugim przykładzie. –