Может ли кто-нибудь рассказать мне о разнице между переменными класса и переменными экземпляра класса?
Ответы:
Переменная класса ( @@) является общей для класса и всех его потомков. Переменная экземпляра класса ( @) не используется потомками класса.
Переменная класса ( @@)
У нас есть класс 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. Я не рекомендую делать это, поскольку это создает запутанный интерфейс, предполагающий, что вы изменяете член объекта.