135

Ho letto "When do Ruby instance variables get set?" ma sono di due menti quando utilizzare le variabili di istanza di classe.Variabile di istanza della classe di Ruby rispetto alla variabile di classe

Le variabili di classe sono condivise da tutti gli oggetti di una classe, le variabili di istanza appartengono a un oggetto. Non c'è molto spazio per usare le variabili di istanza di classe se abbiamo variabili di classe.

Qualcuno potrebbe spiegare la differenza tra questi due e quando usarli?

Ecco un esempio di codice:

class S 
    @@k = 23 
    @s = 15 
    def self.s 
    @s 
    end 
    def self.k 
    @@k 
    end 

end 
p S.s #15 
p S.k #23 

Capisco ora, variabili di classe di istanza non sono passati lungo la catena di ereditarietà!

risposta

195

variabile istanza su una classe:

class Parent 
    @things = [] 
    def self.things 
    @things 
    end 
    def things 
    self.class.things 
    end 
end 

class Child < Parent 
    @things = [] 
end 

Parent.things << :car 
Child.things << :doll 
mom = Parent.new 
dad = Parent.new 

p Parent.things #=> [:car] 
p Child.things #=> [:doll] 
p mom.things #=> [:car] 
p dad.things #=> [:car] 

variabile di classe:

class Parent 
    @@things = [] 
    def self.things 
    @@things 
    end 
    def things 
    @@things 
    end 
end 

class Child < Parent 
end 

Parent.things << :car 
Child.things << :doll 

p Parent.things #=> [:car,:doll] 
p Child.things #=> [:car,:doll] 

mom = Parent.new 
dad = Parent.new 
son1 = Child.new 
son2 = Child.new 
daughter = Child.new 

[ mom, dad, son1, son2, daughter ].each{ |person| p person.things } 
#=> [:car, :doll] 
#=> [:car, :doll] 
#=> [:car, :doll] 
#=> [:car, :doll] 
#=> [:car, :doll] 

Con una variabile di istanza su una classe (non su un'istanza di quella classe) è possibile memorizzare qualcosa di comune a quella la classe senza avere automaticamente le sottoclassi li ottiene (e viceversa). Con le variabili di classe, si ha la comodità di non dover scrivere self.class da un oggetto istanza e (quando si desidera) si ottiene anche la condivisione automatica in tutta la gerarchia di classi.


Unione di questi insieme in un unico esempio, che copre anche le variabili di istanza su istanze:

class Parent 
    @@family_things = [] # Shared between class and subclasses 
    @shared_things = [] # Specific to this class 

    def self.family_things 
    @@family_things 
    end 
    def self.shared_things 
    @shared_things 
    end 

    attr_accessor :my_things 
    def initialize 
    @my_things = []  # Just for me 
    end 
    def family_things 
    self.class.family_things 
    end 
    def shared_things 
    self.class.shared_things 
    end 
end 

class Child < Parent 
    @shared_things = [] 
end 

E poi in azione:

mama = Parent.new 
papa = Parent.new 
joey = Child.new 
suzy = Child.new 

Parent.family_things << :house 
papa.family_things << :vacuum 
mama.shared_things << :car 
papa.shared_things << :blender 
papa.my_things  << :quadcopter 
joey.my_things  << :bike 
suzy.my_things  << :doll 
joey.shared_things << :puzzle 
suzy.shared_things << :blocks 

p Parent.family_things #=> [:house, :vacuum] 
p Child.family_things #=> [:house, :vacuum] 
p papa.family_things #=> [:house, :vacuum] 
p mama.family_things #=> [:house, :vacuum] 
p joey.family_things #=> [:house, :vacuum] 
p suzy.family_things #=> [:house, :vacuum] 

p Parent.shared_things #=> [:car, :blender] 
p papa.shared_things #=> [:car, :blender] 
p mama.shared_things #=> [:car, :blender] 
p Child.shared_things #=> [:puzzle, :blocks] 
p joey.shared_things #=> [:puzzle, :blocks] 
p suzy.shared_things #=> [:puzzle, :blocks] 

p papa.my_things  #=> [:quadcopter] 
p mama.my_things  #=> [] 
p joey.my_things  #=> [:bike] 
p suzy.my_things  #=> [:doll] 
30

Credo che il principale (solo?) Diverso è l'eredità:

class T < S 
end 

p T.k 
=> 23 

S.k = 24 
p T.k 
=> 24 

p T.s 
=> nil 

variabili di classe sono condivisi da tutte le "istanze di classe" (cioè sottoclassi), mentre le variabili di istanza di classe sono specifici solo a quella classe. Ma se non hai intenzione di prolungare la tua classe, la differenza è puramente accademica.

18

#class variabile di istanza sono disponibili solo in classe metodo e non ai metodi di istanza, mentre la variabile di classe è disponibile sia per i metodi di istanza che per i metodi di classe. Anche le variabili di istanza di classe sono perse nella catena di ereditarietà mentre le variabili di classe non lo sono.

class Vars 

    @class_ins_var = "class instance variable value" #class instance variable 
    @@class_var = "class variable value" #class variable 

    def self.class_method 
    puts @class_ins_var 
    puts @@class_var 
    end 

    def instance_method 
    puts @class_ins_var 
    puts @@class_var 
    end 
end 

Vars.class_method 

puts "see the difference" 

obj = Vars.new 

obj.instance_method 

class VarsChild < Vars 


end 

VarsChild.class_method 
12

Come altri hanno detto, le variabili di classe sono condivise tra una determinata classe e le sue sottoclassi. Le variabili di istanza di classe appartengono esattamente a una classe; le sue sottoclassi sono separate.

Perché questo comportamento esiste? Bene, tutto in Ruby è un oggetto, anche classi. Ciò significa che ogni classe ha un oggetto della classe Class (o meglio, una sottoclasse di Class) ad esso corrispondente. (Quando dici class Foo, stai dichiarando una costante e assegnandogli un oggetto di classe.) E ogni oggetto Ruby può avere variabili di istanza, quindi anche gli oggetti di classe possono avere variabili di istanza.

Il problema è che le variabili di istanza sugli oggetti di classe non si comportano in modo normale come di solito si desidera che le variabili di classe si comportino. Solitamente si desidera che una variabile di classe definita in una superclasse sia condivisa con le sue sottoclassi, ma non è così che funzionano le variabili di istanza: la sottoclasse ha il proprio oggetto di classe e quell'oggetto di classe ha le proprie variabili di istanza. Quindi hanno introdotto variabili di classe separate con il comportamento che è più probabile che si desideri.

In altre parole, le variabili di istanza di classe sono una sorta di incidente del progetto di Ruby. Probabilmente non dovresti usarli a meno che tu non sappia esattamente che sono ciò che stai cercando.

+0

quindi la variabile di classe è come una variabile statica in Java? –