Preface
依型態資訊是記錄在宣告在變數之上,或者是執行時期的物件之上,程式語言可以區分為靜態(Static)語言(例如C/C++、Java)與動態(Dynamic)語言(例如Python、JavaScript)。Ruby是動態語言,也就是變數本身並沒有型態資訊,型態的資訊是在執行時期的物件之上,在 Ruby 中有五種變數,包括 區域變數、全域變數、實例變數、類別變數 與 常數。
變數
要建立區域變數,無需宣告型態,只要以小寫字母開頭命名變數並指定值給它,就建立了一個變數,在建立變數之前,嘗試存取某個變數會發生變數未定義的錯誤。例如:
在上例中,一開始建立了一個 x 變數,參考至整數 10,由於變數本身沒有型態,之後你可以將字串"Justin"指定給 x。在 Ruby 中,變數始終是個參考至真實物件的名稱,指定運算只是更改變數的參考對象。例如:
在上例中,x 一開始參考至 1.0 浮點數物件,而後將 x 參考的物件指定給 y 來參考,你可以使用 object_id 方法來取得所參考物件的記憶體位址代表數字,可以看到 x 與 y 都參考同一物件。之後 y 參考至2.0,所以 x 與 y 就參考至不同的物件。
之後+運算後,建立了新的2整數物件,而後指定給 x,所以 x 參考至新的物件。由於變數在Ruby中只是個參考至物件的名稱,所以對於可變動物件,才會有以下的操作結果:
在 Ruby 中,== 常單純比較兩個物件的實質內容是否相同。例如:
上例中,實際上 list1 與 list2 是參考至不同的物件,如果想知道兩個變數是否參考同一物件,除了使用 object_id 得知之外,通常還可以使用 equal? 方法。
相等比較還可以使用 eql? 方法,這個方法通常會檢查變數是否參考同一實例,若否則比較物件是否為同一類別的實例,若是則比較實值是否相同。例如:
上例中,x 與 y 參考的物件分別是 Float 與 Fixnum 的實例,因此 eql? 比較結果為false。
相等比較還可以使用===,通常若===兩邊都是實例,預設實作會比較兩個變數是否參考同一實例,如果不是,會再呼叫==。如果左邊是類別而右且是實例,===比較實例是否由該類別所生成。使用case...when...else 時,就是使用 === 作為依據。
Ruby 區域變數有個特性,直譯器只要看到程式碼中有「變數=值」的語句,就會為建立該變數,這會造成有以下的結果:
在上例中,雖然 if 的區塊不會執行,但直譯器看到 a = 10,就會建立 a 變數,因此之後嘗試顯示 a 的值,是有 a 變數但預設為 nil,然後 b 變數是不存在的,因此出現錯誤。
在 Ruby 中若要建立全域變數,變數名稱只要以 $ 開頭,全域變數一旦建立,整個程式都是可見。例如:
- main.rb
- $x = 10
- x = 20
- puts "%d, %d" % [$x, x]
- load "util.rb"
- puts "%d, %d" % [$x, x]
- $x = 100
- x = 200
在 Ruby 中有一些內建的全域變數,用來儲存整個系統可見的資訊,可查看 Ruby 安裝目錄中的 English.rb,瞭解有哪些全域變數可用。例如:
$$ 可以取得目前程式的行程 ID,要求 English 特性之後,可以用較清楚的名稱使用全域變數,例如 $PID 就等於 $$。
如果變數名稱以大寫作開頭,則稱之為常數,在 Ruby 中,常數並非不能修改,只不過你對常數作第二次修改的話,直譯器會提出警告:
實例變數與類別變數,之後會再說明。
沒有留言:
張貼留言