Может ли кто-нибудь рассказать мне о различии между переменными класса и переменными экземпляра класса?
Разница между переменными класса и переменными экземпляра класса?
Ответ 1
Переменная класса (@@
) разделяется между классом и всеми его потомками. Переменная экземпляра класса (@
) не разделяется потомками класса.
Переменная класса (@@
)
Пусть имеется класс 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
Ответ 2
Сначала вы должны понимать, что классы тоже экземпляры - экземпляры класса Class
.
Как только вы это понимаете, вы можете понять, что класс может иметь связанные с ним переменные экземпляра, как может быть обычный объект (read: non-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 distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"
A переменная класса, с другой стороны, представляет собой комбинацию двух вышеперечисленных, поскольку она доступна для самого 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
.