程式扎記: [ Ruby Gossip ] Basic : 類別 - 類別變數

標籤

2014年11月4日 星期二

[ Ruby Gossip ] Basic : 類別 - 類別變數

Source From Here 
Preface 
接續 單例方法、實例方法、類別方法 的討論。個別類別可以擁有自己的類別方法,也可以擁有自己的類別變數(Class variable),只要變數前加上 @@ 符號就可以定義類別變數。例如: 
 

上例中定義了 Some 的類別變數 @@s,預設外界是不可以直接存取類別變數,你必須為類別變數定義類別方法,外界才可存取,如上例所示。 

類別變數 
可以在實例方法中使用類別變數,不過,你不能在類別方法中使用實例變數,因為類別方法屬於類別擁有,但實例變數屬於實例擁有,類別方法中無法單就 @name 來識別該取得哪個實例的變數值: 
 

在頂層範圍中,如果你如下定義: 
相當於如此定義: 
  1. class Object  
  2.     X = 10  
  3. end  
這可以如下證實: 
>> X = 20
=> 20
>> X
=> 20
>> Object::X
=> 20

類似地,如果你如下定義: 
  1. y = 5  
  2. @@y = 10  
相當於如下定義: 
  1. class Object  
  2.     y = 5  
  3.     @@y = 10  
  4. end  
這可以如下證實: 
 

在 變數範圍 談過,區域變數的範圍就是該區塊,因此上例中 y 是不能在 show_y 中可見的。 

類別既然為 Class 實例,而類別方法實際上為 Class 實例上的單例方法,那麼類別變數就是 Class 實例的實例變數嗎?答案是否定的! Class 實例還是可以擁有自己的實例變數。例如: 
 

@@ 開頭的變數之所以稱為類別變數,是因為它定義了類別範圍內可見的變數,而不是定義 Class 實例的實例變數。注意,@@ 開頭的變數是定義在哪個類別中,它的可視範圍就是在該類別。例如以下是可行的: 
 

@@s 是定義在 Some 中,所以在整個 Some 中都是可見的,不過以下這個範例有個陷阱: 
 

Some 中的 @@s 確實是指在 Some 中可見的類別變數,但是你在頂層定義 Some.s 時,實際上是等同於: 
  1. class Object  
  2.     ...  
  3.     def Some.s  
  4.         @@s  
  5.     end  
  6. end  
這時的 @@s 是想取得 Object 中的 @@s,當然就看不到而發生錯誤,注意以上的 NameError 中的訊息,就是 uninitialized class variable @@s in Object,而不是uninitialized class variable @@s in Some。再來看個有趣的實驗: 
 
定義在 Some.x 中的 @@x,經由 Object.x 中的 @@x 取得的值是相同的。 

注意,在頂層或者說是 Object 類別中,若有 @@變數 與內部類別的 @@變數 同名,則內部類別的 @@變數 會覆蓋外部類別的 @@變數。例如: 
 

這相當於: 
 

但是在非頂層或 Object 中的行為則不同,內部類別的 @@變數「不會」覆蓋外部類別的@@同名變數。例如 
 

Supplement 
Ruby 手冊 - 類別常數

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!