Czy ktoś może mi powiedzieć o różnicy między zmiennymi klas a zmiennymi instancji klas?
91
Czy ktoś może mi powiedzieć o różnicy między zmiennymi klas a zmiennymi instancji klas?
Zmienna klasy ( @@
) jest wspólna dla klasy i wszystkich jej potomków. Zmienna instancji klasy ( @
) nie jest współużytkowana przez potomków klasy.
Zmienna klasy (@@
)
Miejmy klasę Foo ze zmienną klasy @@i
i akcesoriami do czytania i pisania @@i
:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
I klasa pochodna:
class Bar < Foo
end
Widzimy, że Foo i Bar mają tę samą wartość dla @@i
:
p Foo.i # => 1
p Bar.i # => 1
A zmiana @@i
w jednym zmienia to w obu:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Zmienna instancji klasy ( @
)
Stwórzmy prostą klasę ze zmienną instancji klasy @i
i akcesoriami do czytania i pisania @i
:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
I klasa pochodna:
class Bar < Foo
end
Widzimy, że chociaż Bar dziedziczy akcesory dla @i
, nie dziedziczy @i
siebie:
p Foo.i # => 1
p Bar.i # => nil
Możemy ustawić słupki @i
bez wpływu na Foo @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
Najpierw musisz zrozumieć, że klasy to także instancje - instancje
Class
klasy.Kiedy już to zrozumiesz, zrozumiesz, że klasa może mieć przypisane zmienne instancji, tak jak zwykły obiekt (czytaj: nieklasowy).
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!"
Zauważ, że zmienna instancji on
Hello
jest całkowicie niezwiązana ze zmienną instancji w instancji i różni się od niej wHello
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!"
Z drugiej strony zmienna klasowa jest rodzajem kombinacji powyższych dwóch, ponieważ jest dostępna w
Hello
sobie i jej instancjach, a także w podklasachHello
i ich instancjach: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!"
Wiele osób mówi, aby unikać z
class variables
powodu powyższego dziwnego zachowania i zaleca użycieclass instance variables
zamiast.źródło
Chcę również dodać, że możesz uzyskać dostęp do zmiennej klasy (
@@
) z dowolnej instancji klasyclass 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
Ale nie możesz zrobić tego samego dla zmiennej instancji klasy (
@
)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
źródło
Foo.i
, ale jak możesz zrobić to samo dla każdego wystąpienia tej klasy, jakFoo.new.i
?#class
. Osobiście uważam, że#class
zwyczaje wywoływane czegokolwiek, aleself
są to zapachy kodu. Możesz nawet pójść o krok dalej i zaimplementować metody dostępu do instancjii
ii=
delegować je na ich#class
odpowiedniki, w takim przypadku możesz to zrobićFoo.new.i
. Nie polecam tego robić, ponieważ tworzy to mylący interfejs, co sugeruje, że modyfikujesz element członkowski obiektu.