10
class << self 
attr_accessor :n, :totalX, :totalY 
end 

La syntaxe ci-dessus est utilisée pour définir les variables d'instance de classe. Mais quand je pense à ce que la syntaxe implique, cela n'a aucun sens pour moi, donc je me demande si ce type de syntaxe est utilisé pour d'autres types de définitions. Mon point de confusion ici est la suivante:Dans Ruby, existe-t-il des applications connexes de la syntaxe: class << self ... end

class << self 

L'opérateur append signifie normalement « ajouter ce qui est sur le droit à l'objet à gauche ». Mais dans le contexte de ce bloc, comment cela se traduit-il par "mettre le contenu de ce bloc dans la définition de l'instance de classe plutôt que dans l'instance"?

Pour la même raison, je suis confus quant à pourquoi dans un contexte de classe < < auto peut définir des variables d'instance de classe alors que dans une autre, il semble créer des variables de classe comme ici:

class Point 
    # Instance methods go here 
    class << self 
    # Class methods go here 
    end 
end 

Répondre

18

Dans Ruby, vous pouvez rouvrir des classes existantes et ajouter des méthodes. Autrement dit, vous pouvez dire:

class Foo 
    def bob 
    return "hello from bob" 
    end 
end 

ces méthodes sont stockés quelque part dans un dictionnaire interne (peut-être une variable d'instance) de la Foo -class (qui est juste une instance de la Class -class et donc a variables d'instance)

Mais la chose est surprenante, que vous pouvez également ajouter des méthodes à instances des objets existants

foo = Foo.new 
foo2 = Foo.new 

def foo.fred 
    return "I am fred" 
end 


foo.fred #=> "I am fred" 
foo2.fred #=> NoMethodError 

mais Où cette méthode est-elle réellement enregistrée?

Turns out Ruby crée une nouvelle classe dans les coulisses (parfois appelé singleton classe, métaclasse ou eigenclass) qui est insérée dans l'héritage entreheirarchy la Foo -class et son instance.

Ainsi, la relation d'héritage ressemble que:

foo < (eigenclass of foo) < Foo < Class 

(si vous dites foo.superclasse vous ne verrez pas la classe singleton)

le class << X -syntax est un moyen d'accéder à cette classe spéciale, de sorte que vous pouvez le manipuler directement. Les blocs de code suivants sont exactement équivalentes:

def foo.bar 
    return "xy" 
end 

# is exactly the same as 

class << foo 
    def bar 
    return "xy" 
    end 
end 

Ainsi, la similitude entre class Foo < Bar et class << Foo est pas par hasard, il y a l'héritage se passe dans les deux.

Pensez class << X comme « ouvrir la métaclasse de X »

La chose à retenir est que Ruby dans les classes elles-mêmes ne sont que des objets. (Instances de la classe Class) donc si vous dites:

class Foo 
    class << self 
    def k 
     return "x" 
    end 
    end 
end 

(self est lié à Foo dans ce bloc de code) si k est une méthode d'instance des eigenclass de Foo, ce qui en fait une méthode de classe pour Foo

tout cela est plus clairement expliqué dans le chapter about classes of the Pickaxe (la version web ne contient pas les diagrammes, malheureusement) et _whys Seeing Metaclasses Clearly

2

Pensez à la class comme contenant un dictionnaire de membres comprenant tous les accesseurs et variables d'instance. Lorsque vous dites à la classe de «s'ajouter» à «elle-même», vous dites «ajoutez-les au dictionnaire des membres de la classe».

Je vais accorder la notation est un peu hinky, cependant.

+0

Ok - que » s une bonne façon de voir - la classe est en fait un dictionnaire. Mais en fait, vous avez répondu avant d'ajouter mon dernier exemple où, dans un autre contexte, la même syntaxe (selon le livre que je suis en train de lire) produit des méthodes de classe au lieu de méthodes d'instance de classe. Pourquoi l'exemple de classe Point dans la partie inférieure génère-t-il une méthode de classe alors que l'attribut attr_accessor en haut vous donne des attributs qui sont au niveau de l'instance de classe? –

+0

En fait, en utilisant l'explication que vous avez donnée, je peux peut-être répondre à la question dans mon précédent commentaire - la méthode attr_accessor appelle les méthodes instance_variable_set et instance_variable_get de la classe Class. Normalement, cela se traduirait par la création de variables d'instance, mais parce que nous ajoutons au dictionnaire de classe, comme nous le disons, nous créons des variables d'instance de classe. Ok, je pense que je l'ai maintenant. Merci. –

+1

-1 trompeuse, puisque la classe << x ... end ajoute en fait des informations à la métaclasse de x, pas à la classe de x. – rampion

1

Il est vraiment déroutant d'y penser en termes d'opérateur "append". une meilleure façon de voir cela est que tout comme class Foo ouvre la classe Foo, c'est-à-dire qu'il définit 'self' sur l'objet de classe Foo, en le créant si nécessaire, donc class << self ouvre la classe propre de l'objet 'self' actuel. Notez qu'il n'est pas limité à self - pour toute barre d'objet, vous pouvez dire la classe < < pour ouvrir la classe propre de cet objet.

class A 
    def hello 
    print "hello world" 
    end 
end 

a = A.new 
b = A.new 

class << a 
    def goodbye 
    print "goodbye cruel world" 
    end 
end 

a.hello 
b.hello 
a.goodbye 
b.goodbye