Qualcuno può parlarmi della differenza tra variabili di classe e variabili di istanza di classe?
Risposte:
Una variabile di classe ( @@
) è condivisa tra la classe e tutti i suoi discendenti. Una variabile di istanza di classe ( @
) non è condivisa dai discendenti della classe.
Variabile di classe ( @@
)
Facciamo una classe Foo con una variabile di classe @@i
e funzioni di accesso per la lettura e la scrittura @@i
:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
E una classe derivata:
class Bar < Foo
end
Vediamo che Foo e Bar hanno lo stesso valore per @@i
:
p Foo.i # => 1
p Bar.i # => 1
E cambiando @@i
in uno lo cambia in entrambi:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Variabile di istanza di classe ( @
)
Creiamo una classe semplice con una variabile di istanza di classe @i
e funzioni di accesso per la lettura e la scrittura @i
:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
E una classe derivata:
class Bar < Foo
end
Vediamo che sebbene Bar erediti le @i
funzioni di accesso per , non eredita @i
se stesso:
p Foo.i # => 1
p Bar.i # => nil
Possiamo impostare Bar's @i
senza influire su Foo's @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
Per prima cosa devi capire che anche le classi sono istanze - istanze della Class
classe.
Una volta capito questo, puoi capire che una classe può avere variabili di istanza associate ad essa proprio come un normale oggetto (leggi: non classe).
Hello = Class.new
# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")
# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"
Si noti che una variabile di istanza su Hello
è completamente non correlata e distinta da una variabile di istanza su un'istanza diHello
hello = Hello.new
# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")
# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")
# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"
Una variabile di classe d' altra parte è una sorta di combinazione delle due precedenti, in quanto accessibile su Hello
se stessa e sulle sue istanze, nonché sulle sottoclassi di Hello
e sulle loro istanze:
HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new
Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"
Molte persone dicono di evitare a class variables
causa dello strano comportamento di cui sopra e raccomandano invece l'uso di class instance variables
.
Inoltre voglio aggiungere che puoi accedere alla variabile di classe ( @@
) da qualsiasi istanza della classe
class Foo
def set_name
@@name = 'Nik'
end
def get_name
@@name
end
end
a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik
Ma non puoi fare lo stesso per la variabile di istanza di classe ( @
)
class Foo
def set_name
@name = 'Nik'
end
def get_name
@name
end
end
a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil
Foo.i
, ma come puoi fare lo stesso per ogni istanza di questa classe come Foo.new.i
?
#class
. Personalmente penso che gli #class
usi quando vengono chiamati su qualsiasi cosa, ma self
sono odori di codice. Puoi anche fare un ulteriore passo avanti e implementare le funzioni di accesso alle istanze i
e i=
quel delegato ai loro #class
equivalenti, nel qual caso puoi farlo Foo.new.i
. Non consiglio di farlo in quanto crea un'interfaccia confusa, suggerendo che stai modificando un membro dell'oggetto.