在 Swift 中,列舉(Enum)可說是相當好用的,尤其列舉又可以使用 associated value (詳情請見「Swift 的 列舉(Enum) 教學 一文),所以無論在輸入資料或是做比較時,都相當好用。但問題來了,如果我們要比較兩個列舉是否相等,而且列舉的 associated value 又是自訂型態的話,我們如何做比較呢?
答案是很簡單的,我們先看一下下面的範例,假設我們有一個學生和老師的資料結構如下。
struct Student {
let age: Int
let name: String
}
struct Teacher {
let age: Int
let name: String
let students: [Student]
}
而此時,我們的列舉如下
enum Employee {
case teacher(Teacher)
case student(Student)
}
接下來,我們宣告四個變數如下,並將列舉進行比較。
let studentA = Employee.student(Student(age: 18, name: "A"))
let studentB = Employee.student(Student(age: 13, name: "B"))
let studentC = Employee.student(Student(age: 13, name: "B"))
let teacher = Employee.teacher(Teacher(age: 30, name: "B", students: [studentA, studentB]))
let isSameStudnet = studentA == studentACopy //true
let isSameStudnet = studentB == studentACopy //false
let isSameIndentify = studentB == teacher //false
由於我們要比較列舉是否相同,所以勢必得將列舉設為 Equatable,並於列舉內加入「static func == (lhs: Self, rhs: Self)」函式,因此改寫如下。
enum Employee: Equatable {
case teacher(Teacher)
case student(Student)
static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case let (.teacher(lhs), .teacher(rhs)):
return lhs == rhs
case let (.student(lhs), .student(rhs)):
return lhs == rhs
default:
return false
}
}
}
讓我們關注下列這段程式碼,這段程式碼首先先比較兩個列舉是不是都是 teacher,如果是的話,就比較兩個 teacher 列舉值的 associated value 是否相等。如果兩個都是 student ,也一樣比較兩個 student 的 associated value 是否相等。如果兩個列舉值不同,一個是 teacher,一個是 student,那麼就會直接回傳 false。
static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case let (.teacher(lhs), .teacher(rhs)):
return lhs == rhs
case let (.student(lhs), .student(rhs)):
return lhs == rhs
default:
return false
}
}
正因如此,所以 associated value 也必須是 Equatable 型態,也因此 Student 和 Teacher 都必須實做 Equatable。
struct Student: Equatable {
let age: Int
let name: String
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.age == rhs.age && lhs.name == rhs.name
}
}
struct Teacher: Equatable {
let age: Int
let name: String
let students: [Student]
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.age == rhs.age && lhs.name == rhs.name && lhs.students == rhs.students
}
}
或者,你可以用我比較不建議的方法
enum Employee: Equatable {
case teacher(Teacher)
case student(Student)
static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case let (.teacher(lhs), .teacher(rhs)):
return lhs.age == rhs.age && lhs.name == rhs.name && lhs.students == rhs.students
case let (.student(lhs), .student(rhs)):
return lhs.age == rhs.age && lhs.name == rhs.name
default:
return false
}
}
}
延續剛才的範例,如果我們要取出 studentA 的資料,怎麼辦呢?很簡單,只要靠 「if case」 語法就好了。
let studentA = Employee.student(Student(age: 18, name: "A"))
let studentB = Employee.student(Student(age: 13, name: "B"))
let studentC = Employee.student(Student(age: 13, name: "B"))
let teacher = Employee.teacher(Teacher(age: 30, name: "B", students: [studentA, studentB]))
func getStutdentAData() -> Student? {
if case .student(let value) = studentA {
return value
}
return nil
}
在 Swift 中,列舉真的是很實用的工具,大家一定要學會。