Хто-небудь може сказати мені про різницю між змінними класу та змінними екземпляра класу?
Відповіді:
Змінна класу ( @@
) ділиться між класом та всіма його нащадками. Змінна екземпляра класу ( @
) не належить нащадкам класу.
Змінна класу ( @@
)
Давайте матимемо клас 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
Ми можемо встановити бар, @i
не впливаючи на Фу @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
. Я не рекомендую робити це, оскільки це створює заплутаний інтерфейс, припускаючи, що ви змінюєте член об’єкта.