Que fait class << self
en Ruby?
Tout d'abord, la syntaxe de class << foo
ouvre la classe de singleton de foo
(classe propre). Cela vous permet de spécialiser le comportement des méthodes appelées sur cet objet spécifique.
a = 'foo'
class << a
def inspect
'"bar"'
end
end
a.inspect # => "bar"
a = 'foo' # new object, new singleton class
a.inspect # => "foo"
Maintenant, pour répondre à la question: class << self
ouvre la classe singleton de self
, de sorte que les méthodes puissent être redéfinies pour l'objet self
actuel (qui, à l'intérieur d'un corps de classe ou de module, est la classe ou le module lui-même). Généralement, ceci est utilisé pour définir des méthodes class/module ("static"):
class String
class << self
def value_of obj
obj.to_s
end
end
end
String.value_of 42 # => "42"
Cela peut aussi être écrit en abrégé:
class String
def self.value_of obj
obj.to_s
end
end
Ou même plus court:
def String.value_of obj
obj.to_s
end
Dans une définition de fonction, self
fait référence à l'objet avec lequel la fonction est appelée. Dans ce cas, class << self
ouvre la classe singleton pour cet objet; une utilisation de cela est d'implémenter la machine d'état d'un pauvre:
class StateMachineExample
def process obj
process_hook obj
end
private
def process_state_1 obj
# ...
class << self
alias process_hook process_state_2
end
end
def process_state_2 obj
# ...
class << self
alias process_hook process_state_1
end
end
# Set up initial state
alias process_hook process_state_1
end
Ainsi, dans l'exemple ci-dessus, chaque instance de StateMachineExample
a process_hook
aliasée avec process_state_1
, mais notez comment, dans ce dernier, elle peut redéfinir process_hook
(pour self
seulement, n'affectant pas les autres instances StateMachineExample
) à process_state_2
. Ainsi, chaque fois qu'un appelant appelle la méthode process
(qui appelle le process_hook
redéfinissable],), le comportement change en fonction de l'état dans lequel il se trouve.
J'ai trouvé une explication super simple à propos de class << self
, Eigenclass
et d'un type différent de methods
dans ce blog .
En Ruby, trois types de méthodes peuvent être appliqués à une classe:
Les méthodes d'instance et les méthodes de classe sont presque similaires à leurs homonymes dans d'autres langages de programmation.
class Foo
def an_instance_method
puts "I am an instance method"
end
def self.a_class_method
puts "I am a class method"
end
end
foo = Foo.new
def foo.a_singleton_method
puts "I am a singletone method"
end
Une autre façon d'accéder à Eigenclass
(qui inclut les méthodes singleton) consiste à utiliser la syntaxe suivante (class <<
):
foo = Foo.new
class << foo
def a_singleton_method
puts "I am a singleton method"
end
end
vous pouvez maintenant définir une méthode singleton pour self
qui est la classe Foo
elle-même dans ce contexte:
class Foo
class << self
def a_singleton_and_class_method
puts "I am a singleton method for self and a class method for Foo"
end
end
end
Généralement, les méthodes d'instance sont des méthodes globales. Cela signifie qu'ils sont disponibles dans toutes les instances de la classe sur laquelle ils ont été définis. En revanche, une méthode singleton est implémentée sur un seul objet.
Ruby stocke les méthodes dans les classes et toutes les méthodes doivent être associées à une classe. L'objet sur lequel une méthode singleton est définie n'est pas une classe (il s'agit d'une instance d'une classe). Si seules les classes peuvent stocker des méthodes, comment un objet peut-il stocker une méthode singleton? Lorsqu'une méthode singleton est créée, Ruby crée automatiquement une classe anonyme pour stocker cette méthode. Ces classes anonymes sont appelées métaclasses, également appelées classes singleton ou classes propres. La méthode singleton est associée à la métaclasse qui, à son tour, est associée à l'objet sur lequel la méthode singleton a été définie.
Si plusieurs méthodes singleton sont définies dans un même objet, elles sont toutes stockées dans la même métaclasse.
class Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
Dans l'exemple ci-dessus, la classe << z1 change le soi actuel pour pointer vers la métaclasse de l'objet z1; ensuite, il définit la méthode say_hello dans la métaclasse.
Les classes sont également des objets (instances de la classe intégrée appelée Class). Les méthodes de classe ne sont rien de plus que des méthodes singleton associées à un objet de classe.
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Tous les objets peuvent avoir des métaclasses. Cela signifie que les classes peuvent aussi avoir des métaclasses. Dans l'exemple ci-dessus, la classe << self modifie self, de sorte qu'elle pointe vers la métaclasse de la classe Zabuton. Lorsqu'une méthode est définie sans récepteur explicite (la classe/l'objet sur lequel la méthode sera définie), elle est implicitement définie dans la portée actuelle, c'est-à-dire la valeur actuelle de self. Par conséquent, la méthode de remplissage est définie dans la métaclasse de la classe Zabuton. L'exemple ci-dessus n'est qu'un autre moyen de définir une méthode de classe. IMHO, il est préférable d'utiliser la syntaxe def self.my_new_clas_method pour définir les méthodes de classe, car cela facilite la compréhension du code. L'exemple ci-dessus a été inclus afin que nous comprenions ce qui se passe lorsque nous rencontrons la syntaxe de classe << self.
Des informations supplémentaires peuvent être trouvées sur cet article à propos de Ruby Classes .
class Hi
self #=> Hi
class << self #same as 'class << Hi'
self #=> #<Class:Hi>
self == Hi.singleton_class #=> true
end
end
[cela fait self == thing.singleton_class
dans le contexte de son bloc].
hi = String.new
def hi.a
end
hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true
hi
object hérite son #methods
de son #singleton_class.instance_methods
, puis de son #class.instance_methods
.
Nous avons donné ici hi
'singleton class méthode d'instance :a
. Cela aurait pu être fait avec class << hi à la place.hi
's #singleton_class
a toutes les méthodes d'instance hi
's #class
a, et peut-être un peu plus (:a
ici).
[méthodes d'instance de chose#class
et #singleton_class
peut être appliqué directement à chose. quand Ruby voit chose.a, il cherche d'abord: une définition de méthode dans thing.singleton_class.instance_methods, puis dans thing.class.instance_methods]
À propos - ils appellent l'objet singleton class == métaclasse == classe propre.
А méthode singleton est une méthode définie uniquement pour un seul objet.
Exemple:
class SomeClass
class << self
def test
end
end
end
test_obj = SomeClass.new
def test_obj.test_2
end
class << test_obj
def test_3
end
end
puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods
Méthodes de Singleton de SomeClass
test
Méthodes de test_obj de Singleton
test_2
test_3
En fait, si vous écrivez des extensions C pour vos projets Ruby, il n’ya vraiment qu’une façon de définir une méthode Module.
rb_define_singleton_method
Je sais que ces affaires personnelles soulèvent toutes sortes d’autres questions afin que vous puissiez faire mieux en cherchant chaque partie.
Les objets d'abord.
foo = Object.new
Puis-je faire une méthode pour foo?
Sûr
def foo.hello
'hello'
end
Qu'est-ce que je fais avec?
foo.hello
==>"hello"
Juste un autre objet.
foo.methods
Vous obtenez toutes les méthodes Object plus votre nouvelle.
def foo.self
self
end
foo.self
Juste l'objet foo.
Essayez de voir ce qui se passe si vous créez foo à partir d'autres objets comme Class et Module. Les exemples de toutes les réponses sont agréables à jouer, mais vous devez travailler avec différentes idées ou concepts pour vraiment comprendre ce qui se passe dans la façon dont le code est écrit. Alors maintenant, vous avez beaucoup de termes à examiner.
Singleton, Classe, Module, self, Object et Eigenclass ont été ajoutés, mais Ruby ne nomme pas les modèles d’objet de cette façon. Cela ressemble plus à Metaclass. Richard ou __why vous montre l'idée ici. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html Et si le souffle vous emporte, essayez de regarder Ruby Modèle d'objet à la recherche. Les deux vidéos que je connais sur YouTube sont Dave Thomas et Peter Cooper. Ils essaient d'expliquer ce concept aussi. Il a fallu beaucoup de temps à Dave pour l'obtenir, alors ne vous inquiétez pas. Je travaille encore dessus aussi. Sinon, pourquoi serais-je ici? Merci pour votre question. Jetez également un coup d'œil à la bibliothèque standard. Il a un module Singleton juste comme un FYI.
C'est plutôt bien. https://www.youtube.com/watch?v=i4uiyWA8eFk