Rubyで@@ variableはどういう意味ですか?


162

ダブルアットマーク(@@)が前に付いているRuby変数は何ですか?アットマークが前に付いた変数についての私の理解は、それがPHPの次のようにインスタンス変数であるということです。

PHPバージョン

class Person {

    public $name;

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

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

Rubyと同等

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

二重アットマークの@@意味と、単一アットマークとの違いは何ですか?


103
わからないけど、見つめられている感じがします。私は...少しは今のRubyのコードに怖い
corsiKa

2
一般向けのTL; DR:100のうち99回、クラス変数()ではなく、「クラスインスタンス」変数(メソッド@内)を使用します。以下の回答で、理由を説明してください。self@@
WattsInABox 2017

回答:


240

接頭辞付きの変数@インスタンス変数ですが、接頭辞付きの変数@@クラス変数です。次の例を確認してください。その出力は行末のコメントにあり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ものと、@、ではないでしょう。

[更新]

Phrogzがコメントで言及しているように、クラス自体のインスタンス変数でクラスレベルのデータを追跡することは、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)を含めて、期待どおりに動作しない可能性があることを示しました。上記でリンクし記事には、この主題に関する多くの追加情報があります。

また、ほとんどのデータと同様に、dmarkowのコメントに従って、マルチスレッド環境のクラス変数には細心の注意を払う必要があることにも注意してください。


1
サブクラス間でデータを共有する「奇妙な」動作なしに、クラスレベルでインスタンス変数を使用してクラスレベルのデータを追跡する方法を示すコードを含めた場合、この答えは完璧なIMHOになります。
Phrogz、2011年

3
また、クラス変数はマルチスレッド環境(例:Rails)では危険/信頼性が低くなる可能性があることも指摘します
Dylan Markow

うーん... PHPでは静的変数のように聞こえますが、継承部分は異なります。PHPがこのようなものを持っているとは思いません。
Andrew

5
ruby class << self endブロックの機能、特に<<演算子がわかりません。
davidtingsu 2013年

1
混乱している他の人は、これをclass << self参照してください
kapad

37

@-クラスのインスタンス変数
@@-クラス変数、場合によっては静的変数とも呼ばれます

クラス変数は、クラスのすべてのインスタンス間で共有される変数です。つまり、このクラスからインスタンス化されたすべてのオブジェクトに存在する変数値は1つだけです。1つのオブジェクトインスタンスが変数の値を変更すると、その新しい値は基本的に他のすべてのオブジェクトインスタンスに対して変更されます。

クラス変数の考え方のもう1つの考え方は、単一クラスのコンテキスト内のグローバル変数としてです。クラス変数は、変数名の前に2 @文字(@@)を付けることによって宣言されます。クラス変数は作成時に初期化する必要があります


10

@@ クラス変数を示します。つまり、継承できます。

つまり、そのクラスのサブクラスを作成すると、変数が継承されます。したがってVehicle、クラス変数を持つクラスがある@@number_of_wheels場合、作成するclass Car < Vehicleと、クラス変数も含まれます@@number_of_wheels


つまり、そのクラスのサブクラスを作成すると、変数が継承されます。したがってVehicle、クラス変数を持つクラスがある場合、クラス変数@@number_of_wheelsを作成するclass Car < Vehicleと、クラス変数も含まれます@@number_of_wheels
Fareesh Vijayarangam

12
私が持っている場合class Vehicle@number_of_wheels、その後class Car < Vehicleも呼ばれるインスタンス変数を持つことになります@number_of_wheels。クラス変数との主な違いは、クラスが同じ変数を持っていることです。たとえば、一方を変更すると、もう一方も変更されます。
ミシェルティリー

1

モジュール内の@と@@も、クラスがそのモジュールを拡張または含む場合、動作が異なります。

だから与えられた

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

そのため、すべての使用に共通にする変数のモジュールでは@@を使用し、すべての使用コンテキストで個別にしたい変数のモジュールでは@@を使用します。


1

@@は実際にはクラス変数ごとのクラス変数であるため、部分的に正解です。つまり、クラス、そのインスタンス、その子孫クラス、およびそれらのインスタンスによって共有されます。

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

これは出力されます

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

したがって、Person、Student、およびGraduateクラスには同じ@@ variableが1つだけあり、これらのクラスのすべてのクラスおよびインスタンスメソッドは同じ変数を参照します。

クラスオブジェクトで定義されるクラス変数を定義する別の方法があります(各クラスは実際には実際にはクラスクラスであるもののインスタンスですが、それは別の話です)。@@の代わりに@表記を使用しますが、インスタンスメソッドからこれらの変数にアクセスできません。クラスメソッドラッパーが必要です。

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

ここでは、@ peopleは実際には各クラスインスタンスに格納されている変数であるため、クラス階層ではなくクラスごとに1つです。これは出力です:

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

1つの重要な違いは、インスタンスメソッドの@peopleは、Personクラス、Studentクラス、またはGraduateクラスの特定のインスタンスのインスタンス変数を参照するため、インスタンスメソッドからこれらのクラス変数(または言うことができるクラスインスタンス変数)に直接アクセスできないことです。 。

したがって、他の回答では、@ myvariable(単一の@表記)は常にインスタンス変数であると正しく記述されていますが、必ずしもそのクラスのすべてのインスタンスの単一の共有変数ではないという意味ではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.