Perbedaan antara variabel kelas dan variabel contoh kelas?

Jawaban:

152

Variabel kelas ( @@) dibagikan di antara kelas dan semua turunannya. Variabel instance kelas ( @) tidak dibagikan oleh turunan kelas.


Variabel kelas ( @@)

Mari kita memiliki kelas Foo dengan variabel kelas @@i, dan pengakses untuk membaca dan menulis @@i:

class Foo

  @@i = 1

  def self.i
    @@i
  end

  def self.i=(value)
    @@i = value
  end

end

Dan kelas turunan:

class Bar < Foo
end

Kami melihat bahwa Foo dan Bar memiliki nilai yang sama untuk @@i:

p Foo.i    # => 1
p Bar.i    # => 1

Dan mengubah @@isatu perubahan di keduanya:

Bar.i = 2
p Foo.i    # => 2
p Bar.i    # => 2

Variabel instance kelas ( @)

Mari buat kelas sederhana dengan variabel instance kelas @idan aksesor untuk membaca dan menulis @i:

class Foo

  @i = 1

  def self.i
    @i
  end

  def self.i=(value)
    @i = value
  end

end

Dan kelas turunan:

class Bar < Foo
end

Kita melihat bahwa meskipun Bar mewarisi aksesornya @i, ia tidak mewarisi @idirinya sendiri:

p Foo.i    # => 1
p Bar.i    # => nil

Kita dapat mengatur Bar @itanpa mempengaruhi Foo @i:

Bar.i = 2
p Foo.i    # => 1
p Bar.i    # => 2
Wayne Conrad
sumber
1
Mengapa mengembalikan variabel contoh menggunakan metode kelas? Apakah Anda sering mengalami situasi ini?
sekmo
1
@sekmo Pengakses dalam contoh ini mengembalikan variabel instance kelas , yang termasuk dalam kelas, atau variabel kelas , yang termasuk dalam hierarki kelas. Mereka tidak mengembalikan variabel instance biasa yang termasuk dalam instance kelas. Istilah "variabel instan", "variabel instance kelas", dan "variabel kelas" cukup membingungkan, bukan?
Wayne Conrad
72

Pertama, Anda harus memahami bahwa kelas juga merupakan instance - instance Classkelas.

Setelah Anda memahaminya, Anda dapat memahami bahwa kelas dapat memiliki variabel instan yang terkait dengannya seperti halnya objek biasa (baca: non-kelas).

Hello = Class.new

# setting an instance variable on the Hello class
Hello.instance_variable_set(:@var, "good morning!")

# getting an instance variable on the Hello class
Hello.instance_variable_get(:@var) #=> "good morning!"

Perhatikan bahwa variabel contoh pada Hellosama sekali tidak berhubungan dengan dan berbeda dari variabel contoh pada sebuah contoh dariHello

hello = Hello.new

# setting an instance variable on an instance of Hello
hello.instance_variable_set(:@var, :"bad evening!")

# getting an instance variable on an instance of Hello
hello.instance_variable_get(:@var) #=> "bad evening!")

# see that it's distinct from @var on Hello
Hello.instance_variable_get(:@var) #=> "good morning!"

Sebuah variabel kelas di sisi lain adalah semacam kombinasi di atas dua, karena dapat diakses pada Hellodirinya sendiri dan contoh nya, serta pada subclass dari Hellodan contoh mereka:

HelloChild = Class.new(Hello)
Hello.class_variable_set(:@@class_var, "strange day!")
hello = Hello.new
hello_child = HelloChild.new

Hello.class_variable_get(:@@class_var) #=> "strange day!"
HelloChild.class_variable_get(:@@class_var) #=> "strange day!"
hello.singleton_class.class_variable_get(:@@class_var) #=> "strange day!"
hello_child.singleton_class.class_variable_get(:@@class_Var) #=> "strange day!"

Banyak orang mengatakan untuk menghindari class variableskarena perilaku aneh di atas, dan merekomendasikan penggunaan class instance variablessebagai gantinya.

horseyguy
sumber
2
+1 Penjelasan Super! Ini adalah sesuatu yang harus dicerna oleh setiap programmer yang baru mengenal Ruby.
TomZ
0

Juga saya ingin menambahkan bahwa Anda bisa mendapatkan akses ke variabel kelas ( @@) dari setiap contoh kelas

class Foo
  def set_name
    @@name = 'Nik'
  end

  def get_name
    @@name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => Nik

Tetapi Anda tidak dapat melakukan hal yang sama untuk variabel instance kelas ( @)

class Foo
  def set_name
    @name = 'Nik'
  end

  def get_name
    @name
  end
end


a = Foo.new
a.set_name
p a.get_name # => Nik
b = Foo.new
p b.get_name # => nil
Evan Ross
sumber
-1: Ini salah: variabel instance kelas dapat diakses dari setiap instance kelas itu (asalkan ada pengaksesnya). Selain itu, contoh Anda menunjukkan variabel contoh biasa, bukan variabel contoh kelas. Variabel instance kelas dideklarasikan di luar metode, dan secara fundamental berbeda dari variabel instance reguler dan variabel kelas.
The Pellmeister
Bagaimana Anda bisa mendapatkan akses ke variabel instance kelas dari setiap instance kelas itu?
Evan Ross
Sudahkah Anda membaca jawaban Wayne Conrad? Itu benar-benar menjelaskannya. stackoverflow.com/a/3803089/439592
The Pellmeister
Saya tahu Anda bisa mendapatkan akses dari metode kelas seperti Foo.i, tetapi bagaimana Anda dapat melakukan hal yang sama untuk setiap contoh dari kelas ini Foo.new.i?
Evan Ross
Dengan menggunakan #class. Saya pribadi berpikir #classpenggunaan ketika dipanggil apa pun kecuali selfbau kode sekalipun. Anda bahkan dapat melangkah lebih jauh dan mengimplementasikan pengakses instance idan i=delegasi itu ke #classpadanannya, dalam hal ini Anda dapat melakukannya Foo.new.i. Saya tidak menyarankan melakukan itu karena itu membuat antarmuka yang membingungkan, menyarankan Anda memodifikasi anggota objek.
The Pellmeister