Czy ktoś może mi powiedzieć o różnicy między zmiennymi klas a zmiennymi instancji klas?
Odpowiedzi:
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 @@ii 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 @@iw 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 @ii 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 @isiebie:
p Foo.i # => 1
p Bar.i # => nil
Możemy ustawić słupki @ibez 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 Classklasy.
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 Hellojest 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 Hellosobie 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 variablespowodu powyższego dziwnego zachowania i zaleca użycie class instance variableszamiast.
Chcę również dodać, że możesz uzyskać dostęp do zmiennej klasy ( @@) z dowolnej 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 # => 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
Foo.i, ale jak możesz zrobić to samo dla każdego wystąpienia tej klasy, jak Foo.new.i?
#class. Osobiście uważam, że #classzwyczaje wywoływane czegokolwiek, ale selfsą to zapachy kodu. Możesz nawet pójść o krok dalej i zaimplementować metody dostępu do instancji ii i=delegować je na ich #classodpowiedniki, 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.