Ch15. 型態轉換與延展
15.1 檢查型態 以範例來說明,以下有三個類別,分別為University、Teacher以及 Student。 15.1 檢查型態 以範例來說明,以下有三個類別,分別為University、Teacher以及 Student。 Teacher與Student類別皆繼承University類別。
範例程式part1 class University { var name: String init(name: String) { self.name = name } class Teacher: University { var status: String init(name: String, status: String) { self.status = status super.init(name: name) class Student: University { var grade: String init(name: String, grade: String) { self.grade = grade
範例程式part2 // type casting let campus = [ Teacher(name: "Nancy", status: "Professor"), Teacher(name: "Peter", status: "Associated Professor"), Student(name: "Carol", grade: "senior"), Teacher(name: "Mary", status: "Assist Professor"), Student(name: "John", grade: "sophomore") ] var teacherObj = 0 var studentObj = 0 for object in campus { if object is Teacher { teacherObj += 1 } else if object is Student { studentObj += 1 } print("Campus contains \(teacherObj) teachers and \(studentObj) students")
輸出結果 Campus contains 3 teachers and 2 students
15.2 向下轉型 某一類別型態的常數或變數,可能實際參考到子類別的實例。 15.2 向下轉型 某一類別型態的常數或變數,可能實際參考到子類別的實例。 若是,可以利用as型態轉型運算子(type cast operator)向下轉型 (downcast)為子類別型態。 因為向下轉型可能會失敗,所以型態轉型運算子有兩種版本: 選項格式as?,因為無法明確向下轉型知道是否成功,此格式永 遠會回傳一選項值或是nil 。 強制格式as,若你可以明確保證向下轉型會成功,則使用此格 式 。
範例程式 let campus = [ Teacher(name: "Nancy", status: "Professor"), Teacher(name: "Peter", status: "Associated Professor"), Student(name: "Carol", grade: "senior"), Teacher(name: "Mary", status: "Assist Professor"), Student(name: "John", grade: "sophomore") ] for object in campus { if let teacher = object as? Teacher { print("\(teacher.name) is \(teacher.status)") } else if let student = object as? Student { print("\(student.name) is a \(student.grade)") }
輸出結果 Nancy is Professor Peter is Associated Professor Carol is a senior Mary is Assist Professor John is a sophomore
15.3 對AnyObject和Any的型態轉換 Swift提供兩個特定型態的別名,用於非指定型態 :
15.3.1 AnyObject 想要定義任何類別型態的實例時,可利用AnyObject型態的完成。
範例程式 let campusObject: [AnyObject] = [ Teacher(name: "Nancy", status: "Professor"), Teacher(name: "peter", status: "Associated Professor"), Teacher(name: "Mary", status: "Assist Professor") ] for object in campusObject { let teacher = object as! Teacher print("\(teacher.name) is \(teacher.status)") }
輸出結果 Nancy is Professor peter is Associated Professor Mary is Assist Professor
15.3.2 Any 比AnyObject可定義更廣的型態。 除了可建立類別的型態外,也可以用來建立任何型態的變數或陣 列。
範例程式 // Any var data = [Any]() data.append("Hello Swift") data.append(Teacher(name: "Linda", status: "Professor")) for obj in data { print("\(obj)") }
輸出結果 Hello Swift 88.88 0.0 777 0 (10, 20) testAny.Teacher
15.4 延展 延展(extension)程顧名思義就是延伸原來沒有的功能。Swift的延 展與Objective C的類目(category) 類似。
15.4.1 屬性的延展 先從可計算的屬性之延展開始。我們以延展原先的型態Double, 此時多了三個可計算的的屬性,分別是mile、km以及m。此程式 以公里為基點,其它用以換算為公里。 //轉換為公里 extension Double { var mile: Double { return self * 1.6 } var km: Double { return self} var m: Double {return self / 1000} }
範例程式 // 轉換為公里 extension Double { var mile: Double { return self * 1.6 } var km: Double { return self} var m: Double {return self / 1000} } let oneHundredMile = 100.mile print("100 miles is \(oneHundredMile) kilometer") let oneHundredKm = 100.km print("100 miles is \(oneHundredKm) kilometer") let oneHundredMeter = 100.m print("100 meters is \(oneHundredMeter) kilometer")
輸出結果 100 miles is 160.0 kilometer 100 miles is 100.0 kilometer 100 meters is 0.1 kilometer
15.4.2 初始器與方法的延展 除了可延展屬性外,還可以延展初始器與方法。 15.4.2 初始器與方法的延展 除了可延展屬性外,還可以延展初始器與方法。 如有一結構Rectangle,原來有兩個屬性width與height。今加以延 展,增加了初始器init與兩個方法, 分別是getArea()與 setWidthAndHeight。
範例程式part1 // initializer and instance method struct Rectangle { var width = 0.0 var height = 0.0 } extension Rectangle { //initialization init(width2: Double, height2: Double) { width = width2 height = height2 //instant method func getArea() -> Double { return width * height //mutating instance method mutating func setWidthAndHeight(width: Double, height: Double) { self.width = width self.height = height
範例程式part2 var obj = Rectangle(width: 10, height: 20) print("width: \(obj.width), height: \(obj.height)") let objArea = obj.width * obj.height print("area: \(objArea)") obj.setWidthAndHeight(width: 11, height: 21) let objArea2 = obj.width * obj.height print("area: \(objArea2)")
輸出結果 width: 10.0, height: 20.0 area: 200.0 area: 231.0
15.4.3 索引的延展 也可以從Int延展出一索引的實例方法,只要呼叫subscript方法即 可,此方法有一參數,並回傳一Int。
範例程式 // subscript extension Int { subscript(index: Int) -> Int { var base = 1, i=1 while i <= index { base *= 10 i += 1 } return (self / base) % 10 print(123456789[0]) print(123456789[1]) print(123456789[2]) print(123456789[8]) print(123456789[9])
輸出結果 9 8 7 1 0
15.4.4 使用private 取代 fileprivate 在 Swift 3,若在類別或結構中定義 score 是私有的(private),必需 將其定義為 fileprivate ,才能給延展的類別或結構中的函式加以 擷取。 在 Swift 4 中可以直接將私有的資料直接定義為 private 。
範例程式 struct student { var name = "Joe" private var score = 90 } extension student { func display() { print("name: \(name), score: \(score)") var s1 = student() s1.display()
輸出結果 name: Joe, score: 90