程式扎記: [ Ruby Gossip ] Basic : 模組 - 再看變數範圍

標籤

2014年11月18日 星期二

[ Ruby Gossip ] Basic : 模組 - 再看變數範圍

Source From Here 
Preface 
先前談過,在 Ruby 中有五種變數,包括區域變數、全域變數、實例變數、類別變數與常數,先前曾討論過一些範圍(Scope)的問題,在學到模組之後,這邊要正名為區域變數、全域變數、實例變數、類別模組變數 與 常數。以下對變數作個總整理。 

再看變數範圍 
以 $$ 開頭的全域變數是最容易理解的,因為整個程式中隨處可見。以小寫字母開頭的區域變數的範圍也許是其次容易理解的,在 Ruby 中,非常明確的,區域變數就真的只是區域變數,無論它出現在哪個區域,可見範圍就僅止於該區域,不會跨入內嵌的子區域。如果出現在類別區域,就是在類別區域中可見,不會在方法區域中可見。如果出現在模組區域中,就只在模組區域中可見,不會在類別或方法中可見。例如: 
 

如果類別或模組中定義了常數,則類別或模組,或其中的方法都可取用常數(方法中不能設定常數)。常數若定義在類別中,則可以透過「類別名稱::常數」的方式取得。常數若定義在模組中,則可以透過「模組名稱::常數」的方式取得。事實上,類別名稱或模組都必須以大寫名稱作開頭,而大寫名稱在 Ruby 中是定義為常數,所以類別名稱與模組名稱,其實就是個常數。例如: 
 

因此,模組也常被用來作為類別、公用方法或公用常數的名稱空間,而與特定類別相關的公用常數與公用方法則定義在特定類別中。如果類別或模組外定義了常數,則類別或模組內可以直接取用常數,在類別或模組中若設定了同名常數,則是會使用類別或模組中自己定義的常數。例如: 
 

關於 @@ 開頭的變數,在 類別變數 中作過深入的討論,實際上,@@ 開頭的變數,也可以定義在模組中,姑且稱之為模組變數,屬於模組擁有,模組變數必須定義模組方法來取得。例如: 
 

實際上,@@ 開頭的變數,範圍貫穿模組或類別以及當中定義的方法無論是實例方法或是類別方法),而且在 Object 類別中,若有 @@ 變數與內部類別的@@類別變數同名,則外部類別的 @@ 變數會覆蓋內部類別的 @@ 變數在 Object 中定義 @@ 變數,幾乎就等同全域變數了)。因此要小心使用,你可以回顧 類別變數 中看過的幾個例子。 

以 @ 開頭的變數為實例變數,屬於個別物件擁有,可視範圍僅限於物件之內,要取得實例變數,必須為該物件定義實例方法。@ 開頭的變數,並不是只能出現在實例方法中,如果 @ 開頭的變數出現在類別或模組本體,那它就是屬於類別或模組因為它們也是物件,出現在類別或模組方法中時,表示要存取的就是該類別或模組擁有的實例變數。例如: 
 

出現在 Some 本體的 @a,是屬於 Some 類別擁有的實例變數,因此必須透過類別方法 Some.a 取得。出現在實例方法中的 @a,則屬於 Some 產生的 s 實例擁有,因此必須透過 s.a 實例方法存取。那麼,@@ 開頭的變數與 @ 開頭的變數有何不同?來看看這個例子: 
 

這是在 類別變數 討論過的情況,直譯器看到 @@a 時,會往外看類別或模組邊界在哪(而不是看到 Some.a 中的 Some),結果看到的邊界是 Object,但 Object 中並沒有定義 @@a,因此發生錯誤。如果是以下呢? 
 

直譯器看到 @a 時,會看看是透過哪個實例呼叫,結果是 Some,因此取得的是 Some 中定義的 @a。 

@ 開頭的變數一定是在實例上,只是這個實例可能是類別、模組或依類別建構出來的實例;@@ 開頭的變數,可記憶為比 @ 擁有更大可視範圍的意涵,其範圍貫穿模組或類別以及當中定義的方法(無論是實例方法或是類別方法),並需留意 Object 中 @@ 變數幾乎等同全域變數的情況。

沒有留言:

張貼留言

網誌存檔

關於我自己

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