Il semble y avoir un contraste entre les classes singleton de nil
, false
, true
et celle d'une instance d'une classe personnalisée.
i) Les classes singleton de nil
, false
et true
sont désignées par leurs noms de constants assignés:
XXX
ii) La classe singleton de nil
, false
et true
apparaît sur les listes d'ancêtres: p>
a.class.ancestors #=> [A, Object, Kernel, BasicObject]
Pour la classe singleton nommée AClass
d'une instance a
d'une classe personnalisée A
,
a.singleton_class #=> #<Class:#<A:0x00007fda832a7eb0>>
i) AClass
n'est pas référencé par son nom de constante attribué:
class A; end a = A.new AClass = a.singleton_class
ii) AClass
n'apparaît pas dans la liste des ancêtres:
nil.class.ancestors #=> [NilClass, Object, Kernel, BasicObject] false.class.ancestors #=> [FalseClass, Object, Kernel, BasicObject] true.class.ancestors #=> [TrueClass, Object, Kernel, BasicObject]
Est-ce le comportement attendu? Qu'est-ce qui divise nil
, false
, true
d'une part et a
d'autre part? De quoi cette spécification découle-t-elle?
4 Réponses :
Je ne sais pas si cela aide, mais à partir de la documentation pour singleton_class
:
Si obj est
nil
,true
oufalse
, il renvoieNilClass
,TrueClass < / code> ou
FalseClass
, respectivement.
Donc singleton_class
a un comportement spécial pour nil
, true
et false
au lieu du comportement standard de retour la classe singleton des objets.
L'objet retourné ( NilClass
, TrueClass
, FalseClass
) n'est pas spécial car il s'agit bien des classes singleton. Ce qui est spécial, c'est la façon dont ils sont affichés.
Cela peut être réalisé en remplaçant la méthode #inspect
de la classe singleton. classe AClass; Def self.inspect; 'Une classe'; fin; fin; a.singleton_class # => AClass
@ 3limin4t0r Avec les classes non singleton, vous n'avez pas besoin de remplacer inspect
pour faire cela. La question que je me pose est la suivante: pourquoi je dois le remplacer par des classes singleton à l'exception de NilClass
, FalseClass
et TrueClass
.
@sawa merci pour votre commentaire. Je me demande pourquoi ces 3 sont explicitement mentionnés dans la documentation s'il n'y a pas de comportement particulier. C'est une question intéressante et je vais certainement suivre les réponses des autres.
Dans ruby, NilClass
, FalseClass
et TrueClass
ne peuvent avoir qu'une seule instance. C'est pourquoi ils n'ont pas de singleton_class
.
Par exemple:
a = nil def a.foo 'foo' end b = nil b.foo => # foo
Comme nous pourrions le voir, b
répond à la méthode foo
et renvoie foo
string même si nous avons défini la méthode foo
pour la variable a
. Cela signifie que ces 3 classes ne peuvent avoir qu'une seule instance. Et il y a autre chose à souligner que nil
, false
et true
sont des variables mais des pseudo-variables. Ils ne peuvent pas être affectés à des structures de données différentes. Dans un sens, ce sont des variables figées.
Je ne sais pas ce que vous entendez par "ils n'ont pas de singleton_class". Si "ils" pointe vers NilClass
, FalseClass
et TrueClass
, assurez-vous qu'ils n'en ont pas (bien que vous puissiez en créer un: NilClass.singleton_class # => #
), mais pas sûr de ce que vous essayez de dire avec ça. Si «ils» indiquent plutôt nil
, false
et true
, alors vous vous trompez. Ils ont des classes singleton, c'est-à-dire NilClass
, FalseClass
et TrueClass
, comme je l'ai écrit. Et il n'est pas non plus clair comment cela découle du fait que « NilClass
, FalseClass
et TrueClass
ne peuvent avoir qu'une seule instance.
Et il est encore plus difficile de trouver une pertinence entre la dernière partie de votre réponse et ma question.
1. nil
, false
, true
objets
i) Les classes singleton de nil, false et true sont désignées par leurs noms de constante assignés:
Ce n'est pas correct. La méthode singleton_class
de nil
, true
et false
ne renvoie pas leurs classes singleton car elles n'existent pas. Au lieu de cela, il renvoie leurs classes réelles. La raison pour laquelle ces objets n'ont pas de classes singleton est évidente et est bien décrite dans la réponse de @ zeitnot.
Ce comportement est attendu et est documenté ici https : //ruby-doc.com/core/Object.html#method-i-singleton_class
ii) La classe singleton de nil, false et true apparaît sur l'ancêtre listes
Ce n'est pas non plus correct. Étant donné que ces objets n'ont pas de classes singleton, ce que vous voyez dans la liste des ancêtres est leurs classes réelles. Mais même s'ils avaient des classes singleton, vous ne les obtiendriez pas de cette façon (continuez à lire pour savoir pourquoi)
2. une instance a
d'une classe personnalisée A
i) AClass n'est pas référencé par son nom de constante attribué:
AClass = a.singleton_class
Ce code fait référence à AClass
a.singleton_class
. Mais c'est une relation unidirectionnelle (de AClass
à a.singleton_class
). Cela ne fait pas que a.singleton_class
fait référence et renvoie AClass
comme vous vous y attendez.
ii) AClass n'apparaît pas dans la liste des ancêtres:
Pour obtenir une liste d'ancêtres comprenant la classe singleton, exécutez a.singleton_class.ancestors
au lieu de a.class.ancestors
.
class A; end class B < A; end class C < B; end A.ancestors # => [A, ...] B.ancestors # => [B, A, ...] C.ancestors # => [C, B, A, ...]
La méthode ancestors
recherche uniquement la hiérarchie:
a.singleton_class.ancestors #=> [#<Class:#<A:0x000000000191dba0>>, A, Object, Kernel, BasicObject]
Si true
n'a pas de classe singleton comme vous le prétendez, alors sur quelle classe la méthode singleton suivante foo
est-elle définie? def true.foo; fin; true.method (: foo) .owner # => TrueClass
Si vous dites que ce n'est pas une classe singleton, alors qu'est-ce qu'une classe singleton?
Notez ceci: [true, false, nil] .all? {| x | x.singleton_class == x.class}
. Les classes de ces constantes sont renvoyées comme des cas exceptionnels lorsqu'une classe singleton est demandée (voir ici ). Par conséquent, votre foo
se trouve directement sur la classe de true
(c'est-à-dire TrueClass
). Il n'y a aucun autre objet pour lequel x.class == x.singleton_class
est vrai.
@sawa Vous avez répondu à votre propre question. C'est TrueClass
- la classe actuelle. La définition d'une méthode singleton pour ces objets revient à définir une méthode d'instance qui appartient à leur classe réelle
@chumakoff Si vous dites que ce n'est pas une classe singleton, alors qu'est-ce qu'une classe singleton?
@chumakoff Je ne comprends pas non plus votre argument "Mais c'est une relation unidirectionnelle (de AClass
à a.singleton_class
). Cela ne fait pas de un .singleton_class
fait référence à et renvoie AClass
comme prévu. " Lorsque vous avez une classe sans nom, son inspection commence à faire référence à son nom lorsque vous la nommez. b = Class.new => #
Je ne vois pas comment votre argument correspond à cela.
La classe singleton est plutôt bien définie ailleurs , et Je suis sûr que vous savez ce que c'est. Mais ces trois sont spécifiquement chargés de mentir à propos de leur classe singleton , conformément au lien ci-dessus, et de rapporter leur classe réelle lorsqu'ils sont envoyés avec singleton_class
.
@sawa Dans le cas d'une classe singleton, vous n'avez pas de classe sans nom
Un bon exemple dit souvent plus que beaucoup de mots:
foo = FooClass.instance # unfortunately the syntax is not exactly the same foo #=> foo foo.class #=> FooClass foo.singleton_class #=> FooClass
Voyons maintenant les similitudes:
true #=> true true.class #=> TrueClass true.singleton_class #=> TrueClass
require 'singleton' class FooClass include Singleton alias singleton_class class def inspect 'foo' end end
Cela signifie que true.singleton_class
fait référence à sa propre classe au lieu de sa classe singleton. Cela a du sens, puisque true
est un singleton qui fait de sa propre classe la classe singleton par définition. (Puisqu'il s'agit de la classe d'un singleton.)
C’est pareil, mais ce n’est absolument pas ainsi que cela est implémenté dans Ruby. FooClass.send (: new)
fonctionne parfaitement, produisant une autre instance de FooClass
: [FooClass.send (: new), FooClass.send (: new)] .map (&: __ id __). réduire (: ==) # ⇒ false
.
@AlekseiMatiushkin C'est un détail d'exécution. TrueClass est écrit en C tandis que ma classe ci-dessus est écrite en Ruby lui-même. Atteindre exactement le même comportement est assez difficile. L'état d'esprit reste le même. Dans le scénario ci-dessus, vous appelez une méthode privée exprès, qui n'est pas l'interface fournie (les méthodes publiques).
Ces classes contournent l'habituel code> RBASIC () recherche de classe.
Aussi:
BasicObject.new.singleton_class # ⇒ NoMethodError: méthode non définie `singleton_class 'pour #