Ruby 使用手冊

存取器 Accessors

甚麼是存取器?

我們曾在之前的章節討論過實例變數,但尚未深入探討。物件的實例變數即是物件的屬性 (attribute),用以區分出同類別的其他物件。能夠讀寫這些屬性非常重要,若要讀寫便需要稱為屬性存取器 (attribute accessors) 的公開方法(編註:所有實例變數都不公開的,除非透過公開方法存取)。我們等一下就會看到,並不是每次都需要明確地寫出存取器方法,現在先看一下所有的步驟。兩種存取器分別是寫入器 (writer)閱讀器 (reader)

ruby> class Fruit
    |   def set_kind(k)  # 寫入器
    |     @kind = k
    |   end
    |   def get_kind     # 閱讀器
    |     @kind
    |   end
    | end
   nil
ruby> f1 = Fruit.new
   #<Fruit:0xfd7e7c8c>
ruby> f1.set_kind("peach")  # 使用該寫入器
   "peach"
ruby> f1.get_kind           # 使用該閱讀器
   "peach"
ruby> f1                    # 檢驗該物件
   #<Fruit:0xfd7e7c8c @kind="peach">

很簡單吧,我們可以儲存取回想查看的水果資料, 但方法名稱有點冗長。以下例子就比較精簡方便:

ruby> class Fruit
    |   def kind=(k)
    |     @kind = k
    |   end
    |   def kind
    |     @kind
    |   end
    | end
   nil
ruby> f2 = Fruit.new
   #<Fruit:0xfd7e7c8c>
ruby> f2.kind = "banana"
   "banana"
ruby> f2.kind
   "banana"

inspect 方法

先離題一下, 現在你會注意到,我們要直接查看物件時,就會出現 #<anObject:0x83678> 這個難懂的訊息。這只是個預設的行為,我們可以隨意變更。只要加上稱為 inspect 的方法, 就會傳回以合理方式描述物件的字串,包括物件部分或所有實例變數的狀態。

ruby> class Fruit
    |   def inspect
    |     "a fruit of the #{@kind} variety"
    |   end
    | end
   nil
ruby> f2
   "a fruit of the banana variety"

一個相關的方法稱為 to_s (轉換為字串),於輸出物件時使用。一般來說,你可以將 inspect 想像為編寫程式並用以除錯的工具,而 to_s 則是重新定義程式輸出的方式。eval.rb 顯示結果時就會使用 inspect。你可使用 p 方法,輕易地從程式取出除錯輸出。

# 這兩行是相等的:
p anObject
puts anObject.inspect

簡單使用存取器

因為不少實例變數都需要存取器方法,因此 Ruby 提供了一些快捷的方式。

快捷方式 效果
attr_reader :v def v; @v; end
attr_writer :v def v=(value); @v=value; end
attr_accessor :v attr_reader :v; attr_writer :v
attr_accessor :v, :w attr_accessor :v; attr_accessor :w

讓我們善用這些方式加到程式裡吧。首先我們需要一個自動產生出來的閱讀器及寫入器,然後加入新的資訊至 inspect

ruby> class Fruit
    |   attr_accessor :condition
    |   def inspect
    |     "a #{@condition} #{@kind}"
    |   end
    | end
   nil
ruby> f2.condition = "ripe"
   "ripe"
ruby> f2
   "a ripe banana"

更多水果的樂趣

如果沒有人吃成熟的水果,那就讓時間來解決吧。

ruby> class Fruit
    |   def time_passes
    |     @condition = "rotting"
    |   end
    | end
   nil
ruby> f2
   "a ripe banana"
ruby> f2.time_passes
   "rotting"
ruby> f2
   "a rotting banana"

開始前,我們先要說明一個問題。如果我們現在創造第三件水果,那會怎麼樣呢?要記住,指派值予實例變數後,實例變數才會存在。

ruby> f3 = Fruit.new
ERR: failed to convert nil into String

這是因為 inspect 方法發出問題,而且問題很明顯。我們要求它回報水果的種類及狀態,但是 f3 還未獲指派任何屬性。如果我們想的話,可以重新編寫 inspect 方法,讓它可以用 defined? 方法測試實例變數,並只在實例變數存在時才回報,但這樣就可能不是很實用,因為每種水果都有他們的種類與狀態,我們就要確保它們都已經定義。這將在下一節中討論。

Copyright (c) 2005-2008 Mark Slagell,中文翻譯 Ruby Taiwan 社群

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.

A copy of the license is included in the section entitled "GNU Free Documentation License."