Что означает переменная @@в 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

Поэтому используйте @@в модулях для переменных, которые вы хотите использовать для всех своих применений, и используйте @в модулях для переменных, которые вы хотите разделить для каждого контекста использования.