Что означает @@variable в Ruby?
какие переменные Ruby предшествуют знакам double at (@@
)? Мое понимание переменной, предшествующей знаку 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
что делает двойной знак @@
mean, и чем он отличается от одного знака at?
5 ответов
переменная с префиксом @
это переменная, в то время как одна начинаются с @@
- это переменной класс. Проверьте следующий пример; его вывод находится в комментариях в конце 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
, с одним @
не будет.
[обновление]
как упоминает Phrogz в комментариях, это обычная идиома в 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.
@
- переменная экземпляра класса@@
- переменная класса, также называемая в некоторых случаях статической переменной
переменная класса-это переменная, которая является общей для всех экземпляров класса. Это означает, что для всех объектов, созданных из этого класса, существует только одно значение переменной. Если один экземпляр объекта изменяет значение переменной, это новое значение будет существенно изменено для всех других экземпляров объекта.
другой способ мышления мышление переменных класса - это глобальные переменные в контексте одного класса.
Переменные класса объявляются путем префикса имени переменной с двумя @
символы (@@
). Переменные класса должны быть инициализированы во время создания
@@
обозначает переменную класса, т. е. она может быть унаследована.
это означает, что если вы создадите подкласс этого класса, он унаследует переменную. Итак, если у вас есть класс Vehicle
с переменной класс @@number_of_wheels
тогда, если вы создаете class Car < Vehicle
тогда у него тоже будет переменная класса @@number_of_wheels
@ и @@ в модулях также работают по-разному, когда класс расширяет или включает этот модуль.
учитывая
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
поэтому используйте @@ в модулях для переменных, которые вы хотите использовать, и используйте @ в модулях для переменных, которые вы хотите разделить для каждого контекста использования.
ответы частично верны, потому что @@ на самом деле является переменной класса, которая находится в иерархии классов, что означает, что она разделяется классом, его экземплярами и его потомками и их экземплярами.
class Person
@@people = []
def initialize
@@people << self
end
def self.people
@@people
end
end
class Student < Person
end
class Graduate < Student
end
Person.new
Student.new
puts Graduate.people
Это позволит вывести
#<Person:0x007fa70fa24870>
#<Student:0x007fa70fa24848>
таким образом, существует только одна переменная @@для классов Person, Student и Graduate, и все методы класса и экземпляра этих классов относятся к одной и той же переменной.
есть другой способ определения класса переменная, которая определена на объекте класса (помните, что каждый класс на самом деле является экземпляром чего-то, что на самом деле является классом класса, но это другая история). Вы используете @ нотации вместо @@, но вы не можете получить доступ к этим переменным из методов экземпляра. Вам нужно иметь обертки метода класса.
class Person
def initialize
self.class.add_person self
end
def self.people
@people
end
def self.add_person instance
@people ||= []
@people << instance
end
end
class Student < Person
end
class Graduate < Student
end
Person.new
Person.new
Student.new
Student.new
Graduate.new
Graduate.new
puts Student.people.join(",")
puts Person.people.join(",")
puts Graduate.people.join(",")
здесь @people является одиночным для каждого класса вместо иерархии классов, потому что на самом деле это переменная, хранящаяся в каждом экземпляре класса. Это вывод:
#<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38>
#<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608>
#<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8>
одно важное отличие заключается в том, что вы не можете получить доступ к этим переменным класса (или переменным экземпляра класса, которые вы можете сказать) непосредственно из методов экземпляра, потому что @people в методе экземпляра будет ссылаться на переменную экземпляра этого конкретного экземпляра класса Person или Student или Graduate.
поэтому, хотя другие ответы правильно утверждают, что @myvariable (с одной @ нотацией) всегда является переменной экземпляра, это не обязательно означает, что это ни одной общей переменной для всех экземпляров этого класса.