Getter 與 setter 是方法,讓你可以讀取和寫入物件屬性的值。 Crystal 有巨集,這讓為屬性定義 getter 和 setter 變得輕鬆。 巨集是一種在編譯期產生程式碼的方式,之後會在巨集概念中介紹。
在 Ruby 中,這些方法是使用 attr_reader、attr_writer 和 attr_accessor 方法定義的,表面上和 Crystal 的實作非常相似。
Crystal 則將它們定義成 getter、setter 和 property 巨集。
Getter 是一個巨集,它會定義一個回傳實例變數值的方法。
這表示當你想存取實例變數時(在方法中,不含 initialize),不再需要在它前面寫 @;取而代之的是,你可以呼叫 getter 巨集所定義的方法。
getter 巨集可以接受多個實例變數,只要用逗號分隔即可。
# This:
class Person
@name : String
@age : Int32
def name
@name
end
def age
@age
end
end
# Is the same as this:
class Person
@name : String
@age : Int32
getter name, :age
end
如你所見,使用 getter 可以減少你撰寫的程式碼量,也讓程式更好讀。 此外,Ruby 和 Crystal 有一點不同:Crystal 的 getter 巨集同時接受變數名稱和符號作為引數。 符號之後會在符號概念中介紹。
Setter 是一個巨集,它會定義一個設定實例變數值的方法。
這個巨集不常單獨出現,通常會改用 property 巨集。
建立出來的方法會長得像 name_of_method=;其中的 = 就是讓屬性可以被設定的關鍵。
這種方法定義比較特別,因為方法接收的引數放在 = 符號之後。
Crystal 中還有其他幾個特殊方法也使用這種語法,例如 + 方法。
和 getter 巨集一樣,定義 setter 之後,當你想更新實例變數的值時,可以呼叫 setter 巨集所定義的方法。
# This:
class Person
@name : String
@age : Int32
def name=(name : String)
@name = name
end
def age=(age : Int32)
@age = age
end
end
# Is the same as this:
class Person
@name : String
@age : Int32
setter name, :age
end
Property 是一個巨集,它會為實例變數同時定義 getter 和 setter。
class Person
@name : String
@age : Int32
property name, :age
end
在這個練習中,你將會模擬一台秤重機。
初始化時,秤重機應該採用出廠設定,而出廠設定會依機器銷售的地區而有所不同。 因此,這台機器應該要能在初始化時指定精確度,以及是否使用公制。
請實作 WeighingMachine#initialize 方法,它接受兩個引數:precision(型別為 Int32)和 metric(型別為 Bool)。
metric 引數為 true 時,表示機器應該使用公制,否則應該使用英制。
這個 initialize 方法也應該將實例變數 @weight 設為 0.0。
precision = 3
metric = true
vm = WeighingMachine.new(precision, metric)
為了滿足不同的需求,我們讓每台秤重機都能自訂精確度(小數分隔符後面的位數)。
請實作 WeighingMachine#precision 取值方法,回傳秤重機的精確度。
precision = 3
metric = true
vm = WeighingMachine.new(precision, metric)
vm.precision
# => 3
請實作 WeighingMachine#weight 屬性,讓重量可以被取得和設定:
precision = 3
metric = true
wm = WeighingMachine.new(precision, metric)
wm.weight = 60.5
wm.weight
# => 60.5
wm.weigh
# => 60.5
請實作 WeighingMachine#metric= 屬性,讓單位可以被設定。
它應該接受布林值。
precision = 3
metric = true
wm = WeighingMachine.new(precision, metric)
vm.weight = 60.5
wm.metric = false
vm.weigh
# => 133.377