类型转换可以判断实例的类型,也可以将实例看做是其父类或子类的实例。
在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