クラス変数とクラスインスタンス変数の違いは?


回答:


151

クラス変数(@@)は、クラスとそのすべての子孫の間で共有されます。クラスインスタンス変数(@)は、クラスの子孫によって共有されません。


クラス変数(@@

クラス変数を持つクラスFooと、@@i読み書き用のアクセサを作ってみましょう@@i

class Foo

  @@i = 1

  def self.i
    @@i
  end

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

end

そして派生クラス:

class Bar < Foo
end

FooとBarの値が同じであることがわかります@@i

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

そして@@i、一方を変更すると、両方で変更されます。

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

クラスインスタンス変数(@

@i読み書き用のクラスインスタンス変数とアクセサーを使用して、単純なクラスを作成してみましょう@i

class Foo

  @i = 1

  def self.i
    @i
  end

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

end

そして派生クラス:

class Bar < Foo
end

Barはのアクセサを継承しますが@i、それ@i自体は継承しません。

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

@iFooに影響を与えずにBarを設定できます@i

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

1
クラスメソッドを使用してインスタンス変数を返す理由 この状況によく遭遇しますか?
sekmo

1
@sekmoこれらの例のアクセサーは、クラスに属するクラスインスタンス変数、またはクラス階層に属するクラス変数を返します。クラスのインスタンスに属するプレーンなインスタンス変数は返しません。「インスタンス変数」、「クラスインスタンス変数」、および「クラス変数」という用語は非常に混乱しますね。
ウェインコンラッド

72

最初に、クラスもインスタンスであることを理解する必要があります- Classクラスのインスタンス。

これを理解すると、通常の(読み取り:非クラス)オブジェクトと同じように、クラスにインスタンス変数を関連付けることができることを理解できます。

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!"

上でインスタンス変数ことに注意してくださいHelloにインスタンス変数とは完全に無関係と区別されるインスタンスHello

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!"

クラス変数に、それがアクセス可能として一方は、上記の二つの組み合わせの一種でありHello、それ自体とそのインスタンス、並びにのサブクラスにHello及びそのインスタンス。

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!"

多くの人々はclass variables上記の奇妙な振る舞いのために避けるように言い、class instance variables代わりにの使用を勧めます。


2
+1スーパー説明!これは、Rubyを初めて使用するすべてのプログラマが消化する必要があることです。
TomZ

0

また@@、クラスのインスタンスからクラス変数()にアクセスできることを追加します

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

ただし、クラスインスタンス変数(@)に対して同じことを行うことはできません。

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

-1:これは誤りです。クラスインスタンス変数は、そのクラスのすべてのインスタンスからアクセスできます(アクセサが存在する場合)。さらに、例では、クラスインスタンス変数ではなく、通常のインスタンス変数を示しています。クラスインスタンス変数はメソッドの外部で宣言され、通常のインスタンス変数やクラス変数とは根本的に異なります。
ペルマイスター

そのクラスのすべてのインスタンスからクラスインスタンス変数にアクセスするにはどうすればよいですか?
エヴァンロス

ウェイン・コンラッドの答えを読みましたか?それは文字通りそれを説明します。stackoverflow.com/a/3803089/439592
ペルマイスター

のようなクラスのメソッドからアクセスできることは知っていますがFoo.i、このクラスのすべてのインスタンスに対して同じようにするにはどうすればよいFoo.new.iですか?
エヴァンロス

を使用して#class。私は個人的#classには、何かが呼び出されたときの使用法を考えselfていますが、コードの匂いです。あなたも、さらに一歩進み、インスタンスアクセサ実装することができますiし、i=彼らにそのデリゲートを#classあなたが行うことができ、その場合には同等、Foo.new.i。混乱を招くインターフェースが作成されるため、この方法はお勧めしません。オブジェクトメンバーを変更することをお勧めします。
ペルマイスター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.