前一課我們提到所有結構化的資料都可以利用 struct 來定義,將實體世界的人、事、物映射到虛擬世界中,例如學校學生在校務系統中,可能包括姓名、學號、出生年月日、科系、年級、修業成績....等等,用 struct 來設計就非常容易。這裡所說的映射就像這樣,將實體能夠「數位化」的資料抽離出來。
一個物品能夠數位化的資料越多,描述物品的屬性就越多,當然這個虛擬化的結果就越真實。
但是 struct 的本事還不只這些。除了在 struct 的大括號 { } 裡面定義結構化資料,也就是變數或常數之外,還可以定義「函式」!
為什麼要在結構化資料裡面定義函式呢?我們先來看一個範例程式。
// 1-8a struct: 商王年表v3
// Created by Heman, 2021/07/26
// Reference: <https://zh.wikipedia.org/wiki/商朝>
struct 商王 {
var 名號: String
var 即位: Int //西元年
var 在位: Int //年
func 自我介紹() -> String {
let 西元年 = 即位 < 0 ? "西元前\\(abs(即位))年" : "西元\\(即位)年"
let 介紹詞 = "我是商王「\\(名號)」,\\(西元年)即位,在位\\(在位)年。"
return 介紹詞
}
}
let 商湯 = 商王(名號: "大乙湯", 即位: -1558, 在位: 12)
print(商湯.名號, 商湯.即位, 商湯.在位)
print(商湯.自我介紹())
在宣告「商王」的資料類型中,我們增加了一個函式,名稱為「自我介紹」,函式裡面沿用第5課1-5a範例程式裡面的「西元年」運算式:
let 西元年 = 即位 < 0 ? "西元前\\(abs(即位))年" : "西元\\(即位)年"
然後組成一個「介紹詞」:
let 介紹詞 = "我是商王「\\(名號)」,\\(西元年)即位,在位\\(在位)年。"
目的就是將這個「介紹詞」字串當函式回傳值。
我們比較兩行列印的結果:
print(商湯.名號, 商湯.即位, 商湯.在位) //大乙湯 -1558 12
print(商湯.自我介紹()) //我是商王「大乙湯」,西元前1558年即位,在位12年。
後者結果才是我們要的。列印個別的屬性,如「商湯.名號」,只是為了確認資料的正確性。而呼叫「商王.自我介紹()」,有點像讓「商王自我介紹」的意思。注意「商王.自我介紹()」,呼叫函式跟使用屬性一樣,用句號 . 連接,而即使不用給參數,代表函式的 () 還是要寫出來。
所以在 struct { } 裡面定義常數或變數,是在描述這個物品的「屬性」,而定義函式,則是描述物品的「功能」或「動作」,所以如此一來,虛擬化的物品不只是靜態資料,還包括原來物品相對應的功能或我們想設計的動作。