17-Swift型別轉換

weixin_34208283發表於2016-07-12

型別轉換可以判斷例項的型別,也可以將例項看做是其父類或子類的例項。
 在swift中型別轉換使用isas操作符實現,這兩個操作符提供了一種簡單明瞭的方式去檢查值的型別或轉換其他型別。


一、定義類層次為實際例子


可以將型別轉換用在類和子類的層次結構上,檢查特定型別例項的型別並且轉換這個類例項的型別為這個層次結構中的其他型別:

// 人的類
class Person {
    // 名字
    var name:String
    init(name:String) {
        self.name = name
    }
}

// 學生的類,繼承自Person
class Student:Person {
    // 班級
    var grade:String
    init(name:String, grade:String) {
        self.grade = grade
        super.init(name: name)
    }
}

// 工人的類,繼承自Person
class Worker:Person {
    // 具體職業
    var profession:String
    init(name:String, profession:String) {
        self.profession = profession
        super.init(name: name)
    }
}



// 常量陣列
let library = [
    Student(name: "張三", grade: "一年級(1)班"),
    Worker(name: "李明", profession: "教師"),
    Student(name: "李四", grade: "二年級(3)班"),
    Worker(name: "小紅", profession: "醫生"),
    Student(name: "王五", grade: "三年級(6)班"),
]
/** 常量library沒有設定型別,而系統會自動推斷出其型別是Person,
 因為Student和Worker類的共同父類是Person
 */


二、檢查型別


用型別檢查操作符is來檢查一個例項是否屬於特定子型別,若例項屬於那個子型別,型別檢查操作符返回true,否則返回false

// 計算常量陣列library中學生和工作者的個數
var studentCount = 0
var workerCount = 0

for item in library {
    // 判斷例項的型別
    if item is Student {
        studentCount += 1
    }
    else if item is Worker {
        workerCount += 1
    }
}

print("學生個數:\(studentCount),工作者的個數:\(workerCount)")
輸出結果:
學生個數:3,工作者的個數:2


三、向下轉型


某型別的一個常量或變數實際上是屬於一個子類,那麼可以嘗試向下轉到子類型別,用型別轉換操作符as?as!
 而向下轉型可能會失敗,型別轉換操作符有兩種形式。條件形式as?,返回一個試圖向下轉成的型別的可選型別。強制形式as!把試圖向下轉型和強制拆包結果作為一個混合動作。
 當不確定轉型是否成功,建議用條件形式as?。條件形式的型別轉換總是返回一個可選型別的,且向下轉型不可能的,可選值就是為nil,這也就可以檢查向下轉型是否成功。
 只有當確定向下轉型一定會成功時,才使用強制形式as!。但試圖向下轉型為一個不正確型別時,這就會導致程式崩潰。

// 因為library系統自動推斷是Person,即item都是Person型別
for item in library {
    // 嘗試將item向下轉型,即轉為Student型別,轉換成功即輸出對應結果
    if let student = item as? Student {
        print("學生:\(student.name)     班級:\(student.grade)")
    }
    if let worker = item as? Worker {
        print("工作者:\(worker.name)      職業:\(worker.profession)")
    }
}
輸出結果:
學生:張三     班級:一年級(1)班
工作者:李明      職業:教師
學生:李四     班級:二年級(3)班
工作者:小紅      職業:醫生
學生:王五     班級:三年級(6)班

注意: 型別轉換沒有真正改變例項中的值,即是例項根本就是保持不變的,只是簡單地把例項作為它被轉換成的型別來使用。


四、Any和AnyObject的型別轉換


swift中為不確定型別提供了兩種特殊型別別名:
  - AnyObject可以代表任何類的例項;
  - Any可以表示任何型別,包括方法型別;

  • AnyObject型別。例如當我們接收到一個[AnyObject]型別陣列,即是"一個任意型別物件的陣列",此時我們可以使用強制形式的型別轉換來處理陣列中的每個元素:
// 定義一個 `[AnyObject]` 型別的陣列
let someObjects:[AnyObject] = [
    Student(name: "李明", grade: "九年級(3)班"),
    Student(name: "蕭十一", grade: "八年級(7)班"),
    Student(name: "王八", grade: "三年級(5)班")
]
// someObjects陣列只包含Student例項,所以可以直接用強制型別(as!)
for object in someObjects {
    let student = object as! Student
    print("名字:\(student.name)  班級:\(student.grade)")
}
// 更為簡短形式
// 直接將陣列進行型別轉換
for student in someObjects as! [Student] {
    print(">>> 名字:\(student.name)  班級:\(student.grade)")
}
輸出結果:
名字:李明  班級:九年級(3)班
名字:蕭十一  班級:八年級(7)班
名字:王八  班級:三年級(5)班
>>> 名字:李明  班級:九年級(3)班
>>> 名字:蕭十一  班級:八年級(7)班
>>> 名字:王八  班級:三年級(5)班
  • Any型別。使用Any型別來混合不同型別:
// 可以任意型別的陣列trings
var things = [Any]()

// 整形
things.append(0)
// 浮點型
things.append(3.3)
// 整形
things.append(99)
// 字串
things.append("hello swift")
// Student例項
things.append(Student(name: "多多", grade: "幼兒園(小班)"))
// 閉包
things.append({
    (name:String) -> String in
    return "hello \(name)"
})


// 將things陣列中元素對應列印出來
for thing in things {
    switch thing {
    // 轉為整形
    case let someInt as Int:
        print("整形: \(someInt)")
    // 轉為Dounle
    case let someDouble as Double:
        print("浮點型: \(someDouble)")
    // 判斷是否存在字串型別
    case is String:
        print(">>> 存在有字串")
    // 轉為Student型別
    case let student as Student:
        print("名字:\(student.name)  班級:\(student.grade)")
    // 轉為閉包型別
    case let speak as String -> String:
        print(speak("EndEvent"))
    default:
        print("好煩躁,不判斷了,不知道什麼型別")
    }
}
輸出結果:
整形: 0
浮點型: 3.3
整形: 99
>>> 存在有字串
名字:多多  班級:幼兒園(小班)
hello EndEvent


注:xcode7.3環境

相關文章