類型轉換可以判斷實例的類型,也可以將實例看做是其父類或子類的實例。
?在swift中類型轉換使用is
和as
操作符實現,這兩個操作符提供了一種簡單明了的方式去檢查值的類型或轉換其他類型。
一、定義類層次為實際例子
可以將類型轉換用在類和子類的層次結構上,檢查特定類型實例的類型并且轉換這個類實例的類型為這個層次結構中的其他類型:
// 人的類
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