2011-05-04 125 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 

模塊所以使用@@您要共同他們的所有用途的變量,並在模塊使用@對於每個使用上下文你想分開的變量。

相關問題