web-dev-qa-db-ja.com

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

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

PHPバージョン

class Person {

    public $name;

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

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

ルビー相当

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

ダブルアットマーク@@はどういう意味ですか?シングルアットマークとはどう違いますか?

151
Andrew

@で始まる変数はインスタンス変数ですが、@@で始まる変数はクラス変数です。次の例をご覧ください。その出力は、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がクラス間で共有されていることがわかります。 1つのインスタンスに値を設定すると、そのクラスの他のすべてのインスタンス、および@sharedという名前の変数が1つの@である子クラスでさえ、値が変更されます。

[更新]

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を出力する)を含めて、これが期待どおりに100%動作しない可能性があることを示しました。 上記でリンクした記事 には、主題に関する追加情報がたくさんあります。

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

229
Michelle Tilley

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

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

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

36
Shaunak

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

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

10

モジュール内の@と@@も、クラスがそのモジュールを拡張またはインクルードする場合、異なる動作をします。

だから与えられた

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
Tantallion

@@は実際にはクラス階層ごとのクラス変数であり、クラス、そのインスタンス、およびその下位クラスとそのインスタンスで共有されるため、答えは部分的に正しいです。

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(単一の@表記)は常にインスタンス変数であると正しく述べられていますが、必ずしもそのクラスのすべてのインスタンスに対して単一の共有変数ではないという意味ではありません。

1
Cagatay Kalan