Ruby'de @@ değişkeni ne anlama geliyor?


162

Ruby değişkenlerinden önce iki (sign @@) işaretiyle başlıyor ? Bir at işaretinden önce gelen bir değişkeni anlamam, bunun PHP'de olduğu gibi bir örnek değişkeni olmasıdır:

PHP sürümü

class Person {

    public $name;

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

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

Ruby eşdeğeri

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

İşaretteki çifte ne anlama @@geliyor ve işaretteki tek bir kişiden farkı nedir?


103
Bilmiyorum, ama bana baktığı hissine kapılıyorum. Ruby'de kod
yazmaktan

2
TL; kamu için DR: 100 üzerinden 99 kez, sınıf değişkenleri ( ) değil "sınıf örneği" değişkenleri ( yöntemler @içinde ) kullanırdım. Aşağıdaki cevaplarda nedenlerin nedenlerine bakınız. self@@
WattsInABox

Yanıtlar:


240

Ön ekine sahip bir değişken @bir örnek değişkenidir , önekine eklenmiş @@bir değişken bir sınıf değişkenidir . Aşağıdaki örneği inceleyin; çıktıları putssatır sonundaki yorumlarda bulunur :

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

Bunun @@sharedsınıflar arasında paylaşıldığını görebilirsiniz ; birinin örneğini değeri ayarlayarak adlı bir değişken olduğu sınıf ve hatta çocuk sınıfları, diğer tüm örnekleri için değeri değişir @sharedbiriyle, @olmaz.

[Güncelleme]

Phrogz yorumlarda belirtildiği gibi, sınıf düzeyinde verileri sınıfın kendisinde bir örnek değişkeni ile izlemek Ruby'de yaygın bir deyimdir . Bu, zihninizi sarmak için zor bir konu olabilir ve konu hakkında çok fazla ek okuma vardır , ancak onu Classsınıfı değiştirmek olarak düşünün , ancak yalnızca birlikte Classçalıştığınız sınıf örneği . Bir örnek:

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

Bu beklediğiniz gibi% 100 davranmayabilir göstermek için Squareörnek (hangi çıktılar nil) dahil ; Yukarıda bağlantılı makale konuyla ilgili ek bilgi bol vardır.

Ayrıca, çoğu veride olduğu gibi, dmarkow'un yorumuna göre, çok iş parçacıklı bir ortamda sınıf değişkenlerine son derece dikkat etmeniz gerektiğini unutmayın.


1
Alt sınıflar arasında veri paylaşma 'tuhaf' davranışı olmadan sınıf düzeyindeki verileri izlemek için sınıf düzeyinde bir örnek değişkeni nasıl kullanabileceğinizi gösteren bir kod eklerseniz bu yanıt mükemmel IMHO olur.
Phrogz

3
Ayrıca sınıf değişkenlerinin çok iş parçacıklı bir ortamda (örneğin Rails) tehlikeli / güvenilmez olabileceğini de işaret ederim
Dylan Markow

Hmm ... bir şekilde PHP'de statik değişkenler gibi geliyor, ancak kalıtım kısmı farklı. Ben PHP tam olarak böyle bir şey olduğunu sanmıyorum.
Andrew

5
ruby class << self endBloğun ne yaptığını anlamıyorum , özellikle << işleci.
davidtingsu

1
karıştı diğerleri için yaklaşık class << selfbakın bu
kapad

37

@- Sınıfın örnek değişkeni
@@- Bazı durumlarda statik değişken olarak da adlandırılan Sınıf değişkeni

Sınıf değişkeni, sınıfın tüm örnekleri arasında paylaşılan bir değişkendir. Bu, bu sınıftan başlatılan tüm nesneler için yalnızca bir değişken değerinin var olduğu anlamına gelir. Bir nesne örneği değişkenin değerini değiştirirse, bu yeni değer esasen diğer tüm nesne örnekleri için değişir.

Sınıf değişkenlerini düşünmenin başka bir yolu, tek bir sınıf bağlamında küresel değişkenlerdir. Sınıf değişkenleri, değişken adının önüne iki @karakter ( @@) eklenerek bildirilir . Sınıf değişkenleri oluşturma zamanında başlatılmalıdır


10

@@ "Değişken", bir sınıf değişkenini belirtir, yani miras alınabilir.

Bu, söz konusu sınıfın bir alt sınıfını oluşturursanız değişkenin miras alacağı anlamına gelir. VehicleSınıf değişkeniyle bir sınıfınız varsa, o zaman bir sınıf @@number_of_wheelsoluşturursanız class Car < Vehiclesınıf değişkenine de sahip olacaksınız.@@number_of_wheels


Bu, söz konusu sınıfın bir alt sınıfını oluşturursanız değişkenin miras alacağı anlamına gelir. Eğer bir sınıf var Yani eğer Vehiclesınıf değişkeni ile @@number_of_wheelsoluşturup o zaman bir class Car < Vehiclesonra ise çok sınıf değişkeni olacak@@number_of_wheels
Fareesh Vijayarangam

12
Eğer bir class Vehicleile varsa @number_of_wheels, o class Car < Vehiclezaman da adlandırılan bir örnek değişkeni olacaktır @number_of_wheels. Sınıf değişkenleriyle temel fark, sınıfların aynı değişkene sahip olmasıdır, örneğin birini değiştirmek diğerlerini değiştirir.
Michelle Tilley

1

Bir modül bu modülü genişlettiğinde veya içerdiğinde modüllerde @ ve @@ farklı şekilde çalışır.

Çok verildi

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 

Sonra aşağıdaki çıktıları yorum olarak gösterilir

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

Bu nedenle, tüm kullanımlarında ortak olmasını istediğiniz değişkenler için @@ modüllerini kullanın ve her kullanım bağlamı için ayrı olmasını istediğiniz değişkenler için @ modüllerini kullanın.


1

Cevaplar kısmen doğrudur, çünkü @@ aslında sınıf hiyerarşisi başına bir sınıf değişkeni, yani bir sınıf, örnekleri ve onun soyundan gelen sınıflar ve örnekleri tarafından paylaşılır.

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

Bu çıktı

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

Kişi, Öğrenci ve Lisansüstü dersleri için sadece bir @@ değişkeni vardır ve bu sınıfların tüm sınıf ve örnek yöntemleri aynı değişkeni ifade eder.

Bir sınıf nesnesinde tanımlanan bir sınıf değişkenini tanımlamanın başka bir yolu daha vardır (Her sınıfın aslında Sınıf sınıfı olan bir şeyin örneği olduğunu, ancak başka bir hikaye olduğunu unutmayın). @@ yerine @ notasyonu kullanıyorsunuz ancak bu değişkenlere örnek yöntemlerinden erişemiyorsunuz. Sınıf yöntemi sarmalayıcılarına sahip olmanız gerekir.

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

Burada, @people sınıf hiyerarşisi yerine sınıf başına tektir, çünkü aslında her sınıf örneğinde depolanan bir değişkendir. Bu çıktı:

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

Önemli bir fark, bu sınıf değişkenlerine (veya söyleyebileceğiniz sınıf örneği değişkenlerine) doğrudan örnek yöntemlerinden erişememenizdir, çünkü bir örnek yöntemindeki @people, Kişi veya Öğrenci veya Lisansüstü sınıflarının belirli bir örneğinin örnek değişkenine atıfta bulunur .

Diğer cevaplar doğru bir şekilde @ myvariable (single @ notation ile) ifadesinin her zaman bir örnek değişkeni olduğunu belirtmekle birlikte, bu sınıfın tüm örnekleri için tek bir paylaşılan değişken olmadığı anlamına gelmez.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.