Co oznacza @ @ zmienna w Rubim?

Jakie są zmienne Ruby poprzedzone znakiem double at (@@)? Moje zrozumienie zmiennej poprzedzonej znakiem at jest takie, że jest to zmienna instancyjna, jak to w PHP:

Wersja PHP

class Person {

    public $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

Odpowiednik Ruby

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

Co oznacza podwójny znak at @@ i czym się różni od pojedynczego znaku at?

Author: random, 2011-05-05

5 answers

Zmienna z prefiksem @ jest zmienną instancji , podczas gdy jedna z prefiksów @@ jest zmienną klasy . Zobacz poniższy przykład; jego wynik jest w komentarzach na końcu linii 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

Widać, że @@shared jest współdzielone między klasami; ustawienie wartości w instancji one zmienia wartość dla wszystkich innych instancji tej klasy, a nawet klas potomnych, gdzie zmienna o nazwie @shared, z jednym @, nie będzie be.

[Update]

Jak wspomina Phrogz w komentarzach, jest to wspólny idiom w Rubim do śledzenia danych na poziomie klasy za pomocą zmiennej instancji na samej klasie. Może to być trudny temat do ogarnięcia i jest mnóstwo dodatkowego czytania na ten temat, ale pomyśl o tym jako o modyfikacji Class klasy, ale tylko instancja Class klasy, z którą pracujesz. Przykład:

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

I included the Square przykład (który wyprowadza nil), aby wykazać, że może to nie zachowywać się w 100% tak, jak się spodziewasz; Artykuł, który podlinkowałem powyżej , zawiera mnóstwo dodatkowych informacji na ten temat.

Należy również pamiętać, że tak jak w przypadku większości danych, należy bardzo uważać na zmienne klasy w środowisku wielowątkowym , zgodnie z komentarzem dmarkowa.

 211
Author: Michelle Tilley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-05 04:22:19

@ - zmienna instancji klasy
@@ - zmienna klasy, nazywana również zmienną statyczną w niektórych przypadkach

Zmienna klasy jest zmienną współdzieloną między wszystkimi instancjami klasy. Oznacza to, że dla wszystkich obiektów utworzonych z tej klasy istnieje tylko jedna wartość zmiennej. Jeśli jedna instancja obiektu zmieni wartość zmiennej, ta nowa wartość zasadniczo zmieni się dla wszystkich innych instancji obiektu.

Innym sposobem myślenia o zmiennych klasowych jest jako zmienne globalne w kontekście jednej klasy. Zmienne klasy są deklarowane przez prefiks nazwy zmiennej z dwoma znakami @ (@@). Zmienne klasy muszą być zainicjalizowane w czasie tworzenia

 33
Author: Shaunak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-09 11:18:58

@@ oznacza zmienną klasy, tzn. może być dziedziczona.

Oznacza to, że jeśli utworzysz podklasę tej klasy, odziedziczy ona zmienną. Więc jeśli masz klasę Vehicle ze zmienną klasy @@number_of_wheels to jeśli utworzysz class Car < Vehicle to również będzie ona miała zmienną klasy @@number_of_wheels

 9
Author: Fareesh Vijayarangam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-01 03:36:43

@ i @ @ w modułach również działają inaczej, gdy Klasa rozszerza lub zawiera ten moduł.

So given

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 

Następnie otrzymujesz wyniki poniżej pokazane jako komentarze

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

Więc użyj @ @ w modułach dla zmiennych, które chcesz wspólne dla wszystkich ich zastosowań, i użyj @ w modułach dla zmiennych, które chcesz oddzielne dla każdego kontekstu użycia.

 1
Author: Tantallion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-16 04:01:44

Odpowiedzi są częściowo poprawne, ponieważ @ @ jest zmienną klasy, która jest w hierarchii klasowej, co oznacza, że jest współdzielona przez klasę, jej instancje i jej klasy potomne oraz ich instancje.

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

To wyświetli

#<Person:0x007fa70fa24870>
#<Student:0x007fa70fa24848>

Istnieje więc tylko jedna taka sama zmienna @@dla klas Person, Student I Graduate, a wszystkie metody klas I instancji tych klas odnoszą się do tej samej zmiennej.

Istnieje inny sposób definiowania zmiennej klasy, która jest zdefiniowana na obiekcie klasy (pamiętaj, że każda klasa jest rzeczywiście instancją czegoś, co w rzeczywistości jest klasą klasy, ale jest to inna historia). Używasz notacji @ zamiast@@, ale nie możesz uzyskać dostępu do tych zmiennych z metod instancji. Musisz mieć opakowanie metody klasowej.

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(",")

Tutaj @people jest pojedynczą klasą zamiast hierarchii klas, ponieważ jest to zmienna przechowywana na każdej instancji klasy. To jest wyjście:

#<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38>
#<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608>
#<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8> 

Jedną ważną różnicą jest to, że ty nie można uzyskać dostępu do tych zmiennych klasy (lub zmiennych instancji klasy, które można powiedzieć) bezpośrednio z metod instancji, ponieważ @people w metodzie instancji odnosiłaby się do zmiennej instancji tej konkretnej instancji osoby lub klasy studenta lub absolwenta.

Podczas gdy inne odpowiedzi poprawnie stwierdzają, że @ myvariable (z pojedynczą notacją@) jest zawsze zmienną instancyjną, nie musi to oznaczać, że nie jest to pojedyncza wspólna zmienna dla wszystkich instancji tej klasy.

 0
Author: Cagatay Kalan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-04 00:34:32