Может ли кто-нибудь рассказать мне о разнице между переменными класса и переменными экземпляра класса?
91
Может ли кто-нибудь рассказать мне о разнице между переменными класса и переменными экземпляра класса?
Переменная класса ( @@
) является общей для класса и всех его потомков. Переменная экземпляра класса ( @
) не используется потомками класса.
Переменная класса ( @@
)
У нас есть класс Foo с переменной класса @@i
и аксессеры для чтения и записи @@i
:
class Foo
@@i = 1
def self.i
@@i
end
def self.i=(value)
@@i = value
end
end
И производный класс:
class Bar < Foo
end
Мы видим, что Foo и Bar имеют одинаковое значение для @@i
:
p Foo.i # => 1
p Bar.i # => 1
И изменение @@i
в одном меняет его в обоих:
Bar.i = 2
p Foo.i # => 2
p Bar.i # => 2
Переменная экземпляра класса ( @
)
Давайте создадим простой класс с переменной экземпляра класса @i
и средствами доступа для чтения и записи @i
:
class Foo
@i = 1
def self.i
@i
end
def self.i=(value)
@i = value
end
end
И производный класс:
class Bar < Foo
end
Мы видим, что, хотя Bar наследует методы доступа @i
, он не наследует @i
себя:
p Foo.i # => 1
p Bar.i # => nil
Мы можем установить Bar, @i
не затрагивая Foo @i
:
Bar.i = 2
p Foo.i # => 1
p Bar.i # => 2
Сначала вы должны понять, что классы тоже являются экземплярами - экземплярами
Class
класса.Как только вы это поймете, вы сможете понять, что с классом могут быть связаны переменные экземпляра, как с обычным (читай: неклассовым) объектом.
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!"
Обратите внимание, что переменная экземпляра в экземпляре
Hello
полностью не связана и отличается от переменной экземпляра в экземпляреHello
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!"
С другой стороны, переменная класса представляет собой своего рода комбинацию двух вышеперечисленных, поскольку она доступна для
Hello
себя и своих экземпляров, а также для подклассовHello
и их экземпляров: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!"
Многие люди говорят избегать
class variables
из-за странного поведения, описанного выше, и рекомендуютclass instance variables
вместо этого использовать .источник
Также хочу добавить, что вы можете получить доступ к переменной класса (
@@
) из любого экземпляра класса.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
Но вы не можете сделать то же самое для переменной экземпляра класса (
@
)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
, но как вы можете сделать то же самое для каждого экземпляра этого класса, напримерFoo.new.i
?#class
. Я лично считаю, что#class
использование, когда вызывается что-либо, кромеself
запаха кода. Вы даже можете пойти дальше и реализовать средства доступа к экземплярамi
иi=
делегировать их#class
эквивалентам, и в этом случае вы можете это сделатьFoo.new.i
. Я не рекомендую делать это, поскольку это создает запутанный интерфейс, предполагающий, что вы изменяете член объекта.