ダブルアットマーク(@@
)が前に付いた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
ダブルアットマーク@@
はどういう意味ですか?シングルアットマークとはどう違いますか?
@
で始まる変数はインスタンス変数ですが、@@
で始まる変数はクラス変数です。次の例をご覧ください。その出力は、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のコメントによると、 マルチスレッド環境 のクラス変数には非常に注意する必要があることに注意してください。
@
-クラスのインスタンス変数@@
-クラス変数。場合によっては静的変数とも呼ばれます
クラス変数は、クラスのすべてのインスタンス間で共有される変数です。これは、このクラスからインスタンス化されたすべてのオブジェクトに対して1つの変数値のみが存在することを意味します。 1つのオブジェクトインスタンスが変数の値を変更すると、その新しい値は他のすべてのオブジェクトインスタンスに対して本質的に変更されます。
クラス変数の考え方の別の考え方は、単一のクラスのコンテキスト内のグローバル変数としてです。クラス変数は、変数名の前に2つの@
文字(@@
)を付けることで宣言されます。クラス変数は作成時に初期化する必要があります
@@
はクラス変数を示します。つまり、継承できます。
これは、そのクラスのサブクラスを作成すると、変数を継承することを意味します。そのため、クラス変数@@number_of_wheels
を持つクラスVehicle
がある場合、class Car < Vehicle
を作成すると、クラス変数@@number_of_wheels
もあります
モジュール内の@と@@も、クラスがそのモジュールを拡張またはインクルードする場合、異なる動作をします。
だから与えられた
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
したがって、すべての使用に共通する変数にはモジュールで@@を使用し、使用コンテキストごとに分離したい変数にはモジュールで@を使用します。
@@は実際にはクラス階層ごとのクラス変数であり、クラス、そのインスタンス、およびその下位クラスとそのインスタンスで共有されるため、答えは部分的に正しいです。
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(単一の@表記)は常にインスタンス変数であると正しく述べられていますが、必ずしもそのクラスのすべてのインスタンスに対して単一の共有変数ではないという意味ではありません。