What does @@variable mean in Ruby?
什么是Ruby变量前面有双符号(
PHP版本
1 2 3 4 5 6 7 8 9 10 11 12 | class Person { public $name; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } } |
Ruby相当于
1 2 3 4 5 6 7 8 9 10 | class Person def set_name(name) @name = name end def get_name() @name end end |
符号
前缀为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 |
您可以看到
[更新]
正如Phrogz在评论中提到的,在Ruby中使用类本身的实例变量来跟踪类级数据是一种常见的习惯。这可能是一个难以理解的主题,并且有很多关于这个主题的额外阅读,但是想想它是修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 |
我包含
另请注意,与大多数数据一样,您应该在多线程环境中对类变量非常小心,根据dmarkow的评论。
类变量是在类的所有实例之间共享的变量。这意味着对于从此类实例化的所有对象,只存在一个变量值。如果一个对象实例更改了该变量的值,则该新值将基本上针对所有其他对象实例进行更改。
思考类变量的另一种思考方式是在单个类的上下文中作为全局变量。
通过在变量名前加上两个
这意味着如果您创建该类的子类,它将继承该变量。因此,如果你有一个带有类变量
答案是部分正确的,因为@@实际上是一个类变量,它是每个类层次结构,这意味着它由类,它的实例及其后代类及其实例共享。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 |
这将输出
1 2 | #<Person:0x007fa70fa24870> #<Student:0x007fa70fa24848> |
因此,Person,Student和Graduate类只有一个相同的@@变量,这些类的所有类和实例方法都引用相同的变量。
还有另一种定义在类对象上定义的类变量的方法(请记住,每个类实际上是一个实际上是Class类的实例,但它是另一个故事)。您使用@ notation而不是@@但是您无法从实例方法访问这些变量。你需要有类方法包装器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 2 3 | #<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38> #<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608> #<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8> |
一个重要的区别是,您无法直接从实例方法访问这些类变量(或您可以说的类实例变量),因为实例方法中的@people将引用该Person或Student或Graduate类的特定实例的实例变量。
因此,虽然其他答案正确地指出@myvariable(使用单个@表示法)始终是实例变量,但它并不一定意味着它不是该类的所有实例的单个共享变量。
当类扩展或包含该模块时,@和@@ in模块的工作方式也不同。
所以给定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 |
然后,您将下面的输出显示为注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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 |
因此,在模块中使用@@表示您希望它们共同使用的变量,并在模块中使用@,以便为每个使用上下文分别使用变量。