Zmienna instancji w klasie:
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]
Zmienna klasy:
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]
Dzięki zmiennej instancji w klasie (nie w instancji tej klasy) możesz przechowywać coś wspólnego dla tej klasy bez konieczności, aby podklasy automatycznie je otrzymywały (i odwrotnie). Dzięki zmiennym klasowym masz wygodę, że nie musisz pisać self.class
z obiektu instancji i (gdy jest to pożądane) uzyskujesz także automatyczne udostępnianie w całej hierarchii klas.
Scalanie ich razem w jeden przykład, który obejmuje również zmienne instancji dla instancji:
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
A potem w akcji:
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]
self.things
odwoływał się do metodythings
w bieżącym zakresie (w przypadku instancji klasy będzie to metoda instancji), gdzieself.class.things
odwołuje się dothings
metody z klasy bieżącego zakresu (ponownie w przypadku instancji klasy oznaczałoby to metoda klasy).Uważam, że główną (jedyną?) Różnicą jest dziedziczenie:
Zmienne klasy są wspólne dla wszystkich „instancji klasy” (tj. Podklas), podczas gdy zmienne instancji klasy są specyficzne tylko dla tej klasy. Ale jeśli nigdy nie zamierzasz przedłużać zajęć, różnica jest czysto akademicka.
źródło
S.new.s => nil
iS.new.k => 23
.Źródło
Dostępność do metod instancji
Dziedziczenie
źródło
Jak powiedzieli inni, zmienne klas są wspólne dla danej klasy i jej podklas. Zmienne instancji klasy należą do dokładnie jednej klasy; jego podklasy są odrębne.
Dlaczego takie zachowanie istnieje? Cóż, wszystko w Ruby jest przedmiotem - nawet klasy. Oznacza to, że każda klasa ma odpowiadający jej obiekt klasy
Class
(a raczej podklasęClass
). (Kiedy mówiszclass Foo
, naprawdę deklarujesz stałąFoo
i przypisujesz do niej obiekt klasy.) I każdy obiekt Ruby może mieć zmienne instancji, więc obiekty klasy również mogą mieć zmienne instancji.Problem w tym, że zmienne instancji na obiektach klasy tak naprawdę nie zachowują się tak, jak zwykle chcesz, aby zachowały się zmienne klasy. Zwykle chcesz, aby zmienna klasy zdefiniowana w nadklasie była współużytkowana z jej podklasami, ale nie tak działają zmienne instancji - podklasa ma swój własny obiekt klasy, a ten obiekt klasy ma własne zmienne instancji. Wprowadzili więc osobne zmienne klasowe z zachowaniem, które jest bardziej prawdopodobne.
Innymi słowy, zmienne instancji klasy są jakby przypadkiem projektu Ruby. Prawdopodobnie nie powinieneś ich używać, chyba że wiesz, że są tym, czego szukasz.
źródło
Oficjalne FAQ Ruby: Jaka jest różnica między zmiennymi klasowymi a zmiennymi instancji klasy?
Główną różnicą jest zachowanie dotyczące dziedziczenia: zmienne klasy są wspólne dla klasy i wszystkich jej podklas, podczas gdy zmienne instancji klasy należą tylko do jednej konkretnej klasy.
Zmienne klasowe można w pewien sposób postrzegać jako zmienne globalne w kontekście hierarchii dziedziczenia, ze wszystkimi problemami związanymi ze zmiennymi globalnymi. Na przykład zmienna klasy może (przypadkowo) zostać ponownie przypisana przez dowolną z jej podklas, wpływając na wszystkie inne klasy:
Lub klasa przodków może być później ponownie otwarta i zmieniona, z potencjalnie zaskakującymi efektami:
Tak więc, chyba że dokładnie wiesz, co robisz i wyraźnie potrzebujesz tego rodzaju zachowania, lepiej użyj zmiennych instancji klasy.
źródło
Dla osób z doświadczeniem w C ++ możesz być zainteresowany porównaniem z odpowiednikiem C ++:
Jak widzimy,
k
jeststatic
zmienną podobną. Jest to 100% jak zmiennej globalnej, oprócz tego, że jest w posiadaniu przez klasę ( określania zakresów być poprawne). Ułatwia to unikanie kolizji między zmiennymi o podobnych nazwach. Jak każda zmienna globalna, istnieje tylko jedna instancja tej zmiennej, a jej modyfikacja jest zawsze widoczna dla wszystkich.Z drugiej strony
s
jest wartością specyficzną dla obiektu. Każdy obiekt ma własną instancję wartości. W C ++ musisz utworzyć instancję, aby mieć dostęp do tej zmiennej. W Ruby definicja klasy sama w sobie jest instancją klasy (w JavaScript nazywa się to prototypem), dlatego możesz uzyskać dostęps
z klasy bez dodatkowej instancji. Instancję klasy można modyfikować, ale modyfikacjas
będzie specyficzna dla każdej instancji (każdego obiektu typuS
). Zatem modyfikowanie jednego nie zmieni wartości w innym.źródło
Chociaż może wydawać się natychmiastowe użyteczne wykorzystanie zmiennych instancji klasy, ponieważ zmienne instancji klasy są wspólne dla podklas i można się do nich odwoływać zarówno w metodach singleton, jak i instancjach, istnieje pewna wada. Są one wspólne, więc podklasy mogą zmieniać wartość zmiennej instancji klasy, a zmiana na klasę podstawową również będzie miała wpływ, co zwykle jest niepożądanym zachowaniem:
Railsy wprowadzają przydatną metodę o nazwie class_attribute. Jak sama nazwa wskazuje, deklaruje atrybut na poziomie klasy, którego wartość jest dziedziczona przez podklasy. Dostęp do wartości atrybutu class_attribute można uzyskać zarówno w metodach singleton, jak i instancji, podobnie jak w przypadku zmiennej instancji klasy. Jednak ogromną zaletą class_attribute w Railsach jest to, że podklasy mogą zmieniać swoją wartość i nie wpłynie to na klasę nadrzędną.
źródło
self.
każdym razem, gdy chcesz uzyskać dostęp do atrybutuc
, npself.c
. Dokumenty mówią, żedefault:
parametr można przekazać,class_attribute
ale wydaje się, że nie działa ze względu na punkt, o którym właśnie wspomniałemself
.