2010-01-18 5 views
22

Le truc de la classe ruby ​​me donne mal à la tête. Je comprends donné cette ...Variables de classe Ruby

class Foo 
    @var = 'bar' 
end 

... que @var est une variable sur l'instance de la classe créée. Mais comment créer une variable de classe remplaçable de sous-classe?

Voici un exemple de ce que je ferais en Python:

class Fish: 
var = 'fish' 
def v(self): 
    return self.var 

class Trout(Fish): 
    var = 'trout' 

class Salmon(Fish): 
    var = 'salmon' 

print Trout().v() 
print Salmon().v() 

qui sort:

trout 
salmon 

Comment dois-je faire la même chose en Ruby?

+1

shouldn » t que ce soit un @@ var dans le premier bloc de code? – Jean

+0

Je lis "The Well-Grounded Rubyist" (http://manning.com/black2/) par David Black. Il fait un excellent travail en expliquant toutes les nuances dans ce domaine. –

+1

Jean: Non. Si j'utilisais @@ var' alors les sous-classes remplaceraient les classes parentes. Voir le lien de hobodave. Spécifiquement, comment '2' est remplacé dans l'exemple. –

Répondre

8

@var mentionné ci-dessus est appelée variable d'instance de classe, qui est différent de variables d'instance ... lire la réponse here pour voir le diff.

Quoi qu'il en soit c'est l'équivalent du code Ruby:

class Fish 
    def initialize 
    @var = 'fish' 
    end 

    def v 
    @var 
    end 
end 

class Trout < Fish 
    def initialize 
    @var = 'trout' 
    end 
end 

class Salmon < Fish 
    def initialize 
    @var = 'salmon' 
    end 
end 

puts Trout.new.v 
puts Salmon.new.v 
+0

Ce n'est pas vraiment, car vous devez surcharger l'initialisation chaque fois que vous sous-classez. Ce qui n'est pas très utilisable. Il aurait peut-être mieux valu dans mon exemple inclure du code dans initialize. –

21

Pour contraster @ réponse de khelll, celui-ci utilise les variables d'instance sur les objets de classe:

class Fish 
    # an instance variable of this Class object 
    @var = 'fish' 

    # the "getter" 
    def self.v 
    @var 
    end 

    # the "setter" 
    def self.v=(a_fish) 
    @var = a_fish 
    end 
end 

class Trout < Fish 
    self.v = 'trout' 
end 

class Salmon < Fish 
    self.v = 'salmon' 
end 

p Trout.v # => "trout" 
p Salmon.v # => "salmon" 

Edit: de donner des exemples en lecture accès à la variable d'instance de la classe:

class Fish 
    def type_of_fish 
    self.class.v 
    end 
end 

p Trout.new.type_of_fish # => "trout" 
p Salmon.new.type_of_fish # => "salmon" 
+0

Non, pas tout à fait. Vous ne faites pas de Trout.new ou de Salmon.new à la fin. Vous utilisez la classe elle-même. Je veux que * l'instance * obtienne les variables de classe. –

+0

@The Doctor - que diriez-vous maintenant? –

+0

Yup. Je pense que c'est maintenant fonctionnellement équivalent. à la réponse que j'ai donnée. Vous écrivez simplement les accesseurs manuellement. –

2

C'est une erreur commune faite par les codeurs Java venant aussi à Ruby, et l'un des grands sauts conceptuels que j'ai dû faire pour comprendre. Au début, cela semble étrange, mais c'est vraiment l'un des aspects les plus cool de Ruby - tout le code est exécutable, y compris les définitions de classe. Par conséquent, les variables d'instance doivent être déclarées à l'intérieur des méthodes. Cela a à voir avec la façon dont le «soi» est évalué. 'self' est l'objet courant. L'interprète rechercher les appels de méthodes et références variables d'abord dans « soi »:

class Fish 
    @var = "foo" # here 'self' == Fish, the constant which contains the class object 
    def foo 
     # do foo 
    end 
end 

fish = Fish.new 
fish.foo # here 'self' == fish, an instance of Fish 

Dans une définition de classe, « soi » est défini comme l'objet de classe étant définie, de sorte que toutes les références dans une définition de classe se référeront à cet objet de classe, dans ce cas poisson.

Lorsqu'une méthode est appelée sur une instance de Fish, self est défini comme étant le destinataire de l'appel, l'instance particulière de Fish. Donc, en dehors d'une définition de méthode, self est l'objet de classe. À l'intérieur d'une méthode, self est l'instance du récepteur. C'est pourquoi @var en dehors d'une définition de méthode ressemble plus à une variable statique en Java, et @var à l'intérieur d'une définition de méthode est une variable d'instance.

+0

Typo: 'fish.foo' devrait être' fish.var' –

+0

En fait, non. Je n'ai pas défini 'foo' mais le point était que l'interpréteur Ruby verrait 'fish' comme le récepteur de l'appel et réglerait 'self' sur 'fish' afin de résoudre la référence. J'ai ajouté la méthode foo pour plus de clarté. L'appel de 'fish.var' lancerait une erreur NoMethodError. –

+0

Ah. Mon erreur. Merci de l'avoir expliqué. –

4

est ici la version que je fini par déterminer en utilisant le lien de hobodave:

class Fish 
    class << self 
    attr_accessor :var 
    end 

    @var = 'fish' 
    def v 
    self.class.var 
    end 
end 

class Trout < Fish 
    @var = 'trout' 
end 

class Salmon < Fish 
    @var = 'salmon' 
end 

puts (Trout.new).v # => trout 
puts (Salmon.new).v # => salmon 

Notez que subclassing ne nécessite que l'ajout d'un @var - pas besoin de surcharger initialize.

1

Il y a un problème: vous pouvez remplacer @var:
Salmon.var = 'requin' remplacera @var, si
met (Salmon.new) .V # => requin