前面第3課提過,「函式」的作用是當作一般化的工具,就像自動販賣機,不需瞭解內部怎麼運作,只要知道怎麼用就行。「物件類型」也有類似的作用,而且物件類型的作用更多樣,更豐富。
例如,我們可以將1-8a「商王年表」物件類型加以一般化,成為「歷代帝王年表」,讓App內容不拘限於商朝,能學習更多歷史。我們也利用這個機會,學習物件另一個重要觀念:物件初始化。
// 1-8c struct: 歷代帝王年表
// Revised by Heman, 2021/07/28
struct 帝王 {
var 朝代: String
var 名號: String
var 即位: Int //西元年
var 在位: Int //年
init(_ 朝: String = "", 名: String = "", 即: Int = 0, 在: Int = 0) {
朝代 = 朝
名號 = 名
即位 = 即
在位 = 在
}
func 自我介紹() -> String {
let 西元年 = 即位 < 0 ? "西元前\\(abs(即位))年" : "西元\\(即位)年"
let 介紹詞 = "我是\\(朝代)代帝王「\\(名號)」,\\(西元年)即位,在位\\(在位)年。"
return 介紹詞
}
}
let 乞丐 = 帝王()
let 商鞅 = 帝王("商")
let 商湯 = 帝王("商", 名: "大乙湯", 即: -1558, 在: 12)
for 角色 in [乞丐, 商鞅, 商湯] {
print(角色.自我介紹())
}
在資料的結構部分,我們暫只增加一個屬性:朝代,將商王年表推廣為歷代帝王年表。
另外增加了一個非常特別的「函式」稱為 init(),這是 "initializer" (初始化函式)的簡寫。這個函式特別的地方,在於「不用 func 宣告,而且不要任何回傳值」。
初始化函式 init() 最重要的功能,就是必須把所有的物件屬性「初始化」,也就是指定初始值。
所以這裡的 init() 需要4個參數:朝、名、即、在,分別對應4個屬性:朝代、名號、即位、在位。而這4個參數我們都給了「預設值」,前面提過,如果函式參數有預設值,那麼在呼叫時,這個參數是可以省略的。
所以我們可以這樣來使用物件類型:
let 乞丐 = 帝王()
不需輸入任何參數,全部用預設值來初始化物件的屬性。也不用特別寫出 init(),每次使用物件類型就會自動呼叫初始化函式。
而且再注意到 init() 第一個參數名稱前面有加底線,這代表呼叫時,這個參數名稱可省略,所以只要給參數值就可以:
let 商鞅 = 帝王("商")
如果要帶入所有的參數值,最完整的呼叫方式就類似之前的做法,但是改用 init() 的參數名稱,而不是物件的屬性名稱,同時第一個參數名稱可省略:
let 商湯 = 帝王("商", 名: "大乙湯", 即: -1558, 在: 12)