Переменная экземпляра в классе:
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]
Переменная класса:
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]
С помощью переменной экземпляра в классе (не в экземпляре этого класса) вы можете хранить что-то общее с этим классом, не имея подклассов, автоматически получающих их (и наоборот). С переменными класса вы можете не писать self.class
из объекта экземпляра, и (когда это желательно) вы также получаете автоматический общий доступ по всей иерархии классов.
Объединяя их вместе в один пример, который также охватывает переменные экземпляра в экземплярах:
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
И тогда в действии:
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
ссылается на методthings
в текущей области (в случае экземпляра класса это будет метод экземпляра), гдеself.class.things
ссылается наthings
метод из класса текущей области (снова в случае экземпляра класса это будет означать метод класса).Я считаю, что главное (только?) Другое наследование:
Переменные класса являются общими для всех «экземпляров класса» (то есть подклассов), тогда как переменные экземпляра класса специфичны только для этого класса. Но если вы никогда не собираетесь расширять свой класс, разница чисто академическая.
источник
S.new.s => nil
иS.new.k => 23
.Источник
Доступность для методов экземпляра
наследуемости
источник
Как уже говорили другие, переменные класса являются общими для данного класса и его подклассов. Переменные экземпляра класса принадлежат ровно одному классу; его подклассы являются отдельными.
Почему такое поведение существует? Ну, все в Ruby - это объект, даже классы. Это означает, что каждый класс имеет объект класса
Class
(или, скорее, подклассClass
), соответствующий ему. (Когда вы говоритеclass Foo
, вы действительно объявляете постояннуюFoo
и присваиваете ей объект класса.) И каждый объект Ruby может иметь переменные экземпляра, поэтому объекты класса также могут иметь переменные экземпляра.Проблема в том, что переменные экземпляра на объектах класса на самом деле ведут себя не так, как вы обычно хотите, чтобы переменные класса вели себя. Обычно вы хотите, чтобы переменная класса, определенная в суперклассе, использовалась совместно с его подклассами, но это не так, как работают переменные экземпляра - у подкласса есть свой собственный объект класса, а у этого объекта класса есть свои собственные переменные экземпляра. Таким образом, они представили отдельные переменные класса с поведением, которое вы, скорее всего, захотите.
Другими словами, переменные экземпляра класса являются своего рода случайностью дизайна Руби. Вы, вероятно, не должны использовать их, если вы не знаете, что именно они ищут.
источник
Официальный Ruby FAQ: В чем разница между переменными класса и переменными экземпляра класса?
Основным отличием является поведение, касающееся наследования: переменные класса совместно используются классом и всеми его подклассами, в то время как переменные экземпляра класса принадлежат только одному конкретному классу.
Переменные класса в некотором роде можно рассматривать как глобальные переменные в контексте иерархии наследования со всеми проблемами, связанными с глобальными переменными. Например, переменная класса может (случайно) быть переназначена любым из ее подклассов, затрагивая все другие классы:
Или, класс предка мог позже быть открыт и изменен с возможно удивительными эффектами:
Поэтому, если вы точно не знаете, что делаете, и явно не нуждаетесь в таком поведении, лучше использовать переменные экземпляра класса.
источник
Для тех, кто имеет опыт работы с C ++, вас может заинтересовать сравнение с эквивалентом C ++:
Как мы видим,
k
этоstatic
как переменные. Это на 100% похоже на глобальную переменную, за исключением того, что она принадлежит классу ( ограничена областью действия ). Это позволяет избежать конфликтов между одноименными переменными. Как и любая глобальная переменная, существует только один экземпляр этой переменной, и ее изменение всегда видны всем.С другой стороны,
s
это объект специфического значения. У каждого объекта есть свой экземпляр значения. В C ++ вы должны создать экземпляр, чтобы иметь доступ к этой переменной. В Ruby определение класса само по себе является экземпляром класса (в JavaScript это называется прототипом), поэтому вы можете получить доступs
из класса без дополнительных реализаций. Экземпляр класса может быть изменен, но модификацияs
будет специфичной для каждого экземпляра (каждого объекта типаS
). Таким образом, изменение одного не изменит значения в другом.источник
Хотя может показаться полезным сразу использовать переменные экземпляра класса, поскольку переменные экземпляра класса являются общими для подклассов, и на них можно ссылаться как в одноэлементных, так и в экземплярах методов, существует существенный недостаток. Они являются общими, и поэтому подклассы могут изменять значение переменной экземпляра класса, и это изменение также повлияет на базовый класс, что обычно является нежелательным поведением:
Rails представляет удобный метод с именем class_attribute. Как следует из названия, оно объявляет атрибут уровня класса, значение которого наследуется подклассами. Доступ к значению class_attribute возможен как в методе singleton, так и в экземпляре, как в случае с переменной экземпляра класса. Однако огромное преимущество class_attribute в Rails состоит в том, что подклассы могут изменять свое собственное значение, и это не повлияет на родительский класс.
источник
self.
каждый раз, когда хотите получить доступ к атрибутуc
, напримерself.c
. В документах говорится, чтоdefault:
параметр можно передать,class_attribute
но он не работает из-за того, о чем я только что упомянулself
.