2011-05-04 104 views
126

什么是红色变量前加双号(@@)?我前面有一个at符号变量的理解是,它是一个实例变量,像这样在PHP:Ruby中@@变量的含义是什么?

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 

什么双在标志@@的意思是,它与标志上的单个标志有什么不同?

+77

我不知道,但我感觉它盯着我。我现在有点害怕在Ruby中编写代码... – corsiKa 2011-05-04 21:34:58

+0

TL;公众的DR:100次中的99次,我会使用“类实例”变量('@'在'self'方法内)而不是类变量''@@)。请看下面答案中的原因。 – WattsInABox 2017-04-24 15:52:51

回答

188

@前缀的变量是实例变量,而一个与@@前缀是类变量。看看下面的例子;其输出是评价在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中常见的成语有一个实例类本身变量跟踪类级别的数据。这可能是一个棘手的问题,围绕你的想法,有很多additional reading关于这个问题,但认为它是修改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%; article I linked above有关于此主题的大量附加信息。

请注意,与大多数数据一样,根据dmarkow的评论,您应该非常小心multithreaded environment中的类变量。

+1

这个答案将是完美的恕我直言,如果你包含的代码展示了如何在类级别使用实例变量来跟踪类级别的数据,而不需要在子类之间共享数据的“怪异”行为。 – Phrogz 2011-05-04 22:05:14

+2

我还要指出,类变量在多线程环境中可能是危险/不可靠的(例如Rails) – 2011-05-04 22:06:03

+0

嗯......它听起来像PHP中的静态变量,但继承部分不同。我不认为PHP有​​这样的东西。 – Andrew 2011-05-04 23:17:43

9

@@表示类变量,即它可以被继承。

这意味着如果您创建该类的子类,它将继承该变量。所以,如果你有一个类Vehicle与类,然后变量@@number_of_wheels如果你创建一个class Car < Vehicle那么它也将有类变量@@number_of_wheels

+0

这是什么意思? – Andrew 2011-05-04 21:42:28

+0

这意味着如果您创建该类的子类,它将继承该变量。所以,如果你有一个类'Vehicle'的类变量'@@ number_of_wheels',那么如果你创建一个'Class Car 2011-05-04 21:56:08

+12

如果我有一个class Vehicle '用'@ number_of_wheels',然后'class Car 2011-05-04 22:02:58

32

@ - 类的实例变量
@@ - 类变量,也被称为静态变量在某些情况下

类变量是一个类的所有实例之间共享的变量。这意味着对于从此类实例化的所有对象,只有一个变量值存在。如果一个对象实例更改变量的值,那么对于所有其他对象实例,该新值本质上将发生更改。

思考类变量的另一种思维方式是在单个类的上下文中作为全局变量。 通过在变量名前加上两个@字符(@@)来声明类变量。类变量必须在创建时被初始化

0

@ =实例变量其中作为 @@ =类变量

实例变量是类似物,其是与共享实例/以便访问一个类 的对象我们需要为该实例变量定义setter和getters

而类变量是类似的,它在类 的所有实例/对象之间共享,换言之,您可以说它是全局的变量,所以全局变量可以全局访问

0

@和@@模块在类扩展或包含该模块时的工作方式也不同。

因此,考虑

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 

模块所以使用@@您要共同他们的所有用途的变量,并在模块使用@对于每个使用上下文你想分开的变量。