Что означает переменная @@в Ruby?
Каковы переменные Ruby, которым предшествуют двойные знаки (@@
)? Мое понимание переменной, которой предшествует знак at, заключается в том, что она является переменной экземпляра, как это в PHP:
Версия PHP
class Person {
public $name;
public function setName($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
Рубиновый эквивалент
class Person
def set_name(name)
@name = name
end
def get_name()
@name
end
end
Что означает знак двойного знака @@
и как он отличается от одного знака?
Ответы
Ответ 1
Переменная с префиксом @
- это переменная экземпляра, а одна префикс с @@
- это переменная класса. Посмотрите следующий пример; его вывод находится в комментариях в конце строк puts
:
class Test
@@shared = 1
def value
@@shared
end
def value=(value)
@@shared = value
end
end
class AnotherTest < Test; end
t = Test.new
puts "t.value is #{t.value}" # 1
t.value = 2
puts "t.value is #{t.value}" # 2
x = Test.new
puts "x.value is #{x.value}" # 2
a = AnotherTest.new
puts "a.value is #{a.value}" # 2
a.value = 3
puts "a.value is #{a.value}" # 3
puts "t.value is #{t.value}" # 3
puts "x.value is #{x.value}" # 3
Вы можете видеть, что @@shared
разделяется между классами; установка значения в экземпляре одного изменяет значение для всех других экземпляров этого класса и даже дочерних классов, где переменная с именем @shared
с одним @
не будет.
[Обновление]
Как упоминает Фрогз в комментариях, это обычная идиома в Ruby для отслеживания данных на уровне класса с переменной экземпляра в самом классе. Это может быть сложным предметом для вашего ума, и есть много дополнительных чтений по этому вопросу, но подумайте об этом как о модификации класса Class
, но только экземпляр класса Class
, с которым вы работаете. Пример:
class Polygon
class << self
attr_accessor :sides
end
end
class Triangle < Polygon
@sides = 3
end
class Rectangle < Polygon
@sides = 4
end
class Square < Rectangle
end
class Hexagon < Polygon
@sides = 6
end
puts "Triangle.sides: #{Triangle.sides.inspect}" # 3
puts "Rectangle.sides: #{Rectangle.sides.inspect}" # 4
puts "Square.sides: #{Square.sides.inspect}" # nil
puts "Hexagon.sides: #{Hexagon.sides.inspect}" # 6
Я включил пример Square
(который выводит nil
), чтобы продемонстрировать, что это может не соответствовать 100%, как вы ожидаете; в статье приведенной выше, есть много дополнительной информации по этому вопросу.
Также имейте в виду, что, как и в большинстве данных, вы должны быть очень осторожны с переменными класса в многопоточной среде в соответствии с комментарием dmarkow.
Ответ 2
@
- Переменная экземпляра класса
@@
- переменная класса, также называемая как статическая переменная в некоторых случаях
Переменная класса - это переменная, которая разделяется между всеми экземплярами класса. Это означает, что для всех объектов, созданных из этого класса, существует только одно значение переменной. Если один экземпляр объекта изменяет значение переменной, это новое значение существенно изменится для всех других экземпляров объекта.
Другой способ мышления переменных класса - это глобальные переменные в контексте одного класса.
Переменные класса объявляются путем префикса имени переменной двумя символами @
(@@
). Переменные класса должны быть инициализированы во время создания
Ответ 3
@@
обозначает переменную класса, то есть ее можно наследовать.
Это означает, что если вы создадите подкласс этого класса, он наследует переменную. Поэтому, если у вас есть класс Vehicle
с переменной класса @@number_of_wheels
, то если вы создадите class Car < Vehicle
, то он тоже будет иметь переменную класса @@number_of_wheels
Ответ 4
@= переменная экземпляра, где as
@@= переменная класса
переменная экземпляра похожа на то, что является общим с экземпляром/объектами класса
для доступа к переменной экземпляра нам нужно определить сеттеры и геттеры для этой переменной экземпляра
тогда как переменная класса похожа на то, что разделяется между всеми экземплярами/объектами класса
или, другими словами, u может сказать, что это глобальная переменная, поэтому глобальную переменную можно получить глобально
Ответ 5
@и @@в модулях также работают по-разному, когда класс расширяет или включает этот модуль.
Итак, данный
module A
@a = 'module'
@@a = 'module'
def get1
@a
end
def get2
@@a
end
def set1(a)
@a = a
end
def set2(a)
@@a = a
end
def self.set1(a)
@a = a
end
def self.set2(a)
@@a = a
end
end
Затем вы получаете выходы, показанные ниже как комментарии
class X
extend A
puts get1.inspect # nil
puts get2.inspect # "module"
@a = 'class'
@@a = 'class'
puts get1.inspect # "class"
puts get2.inspect # "module"
set1('set')
set2('set')
puts get1.inspect # "set"
puts get2.inspect # "set"
A.set1('sset')
A.set2('sset')
puts get1.inspect # "set"
puts get2.inspect # "sset"
end
class Y
include A
def doit
puts get1.inspect # nil
puts get2.inspect # "module"
@a = 'class'
@@a = 'class'
puts get1.inspect # "class"
puts get2.inspect # "class"
set1('set')
set2('set')
puts get1.inspect # "set"
puts get2.inspect # "set"
A.set1('sset')
A.set2('sset')
puts get1.inspect # "set"
puts get2.inspect # "sset"
end
end
Y.new.doit
Поэтому используйте @@в модулях для переменных, которые вы хотите использовать для всех своих применений, и используйте @в модулях для переменных, которые вы хотите разделить для каждого контекста использования.