某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试用类型转换操作符(as?
或 as!
)向下转到它的子类型。
因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式 as?
返回一个你试图向下转成的类型的可选值。强制形式 as!
把试图向下转型和强制解包转换结果结合为一个操作。
当你不确定向下转型可以成功时,用类型转换的条件形式(as?
)。条件形式的类型转换总是返回一个可选值,并且若下转是不可能的,可选值将是 nil
。这使你能够检查向下转型是否成功。
只有你可以确定向下转型一定会成功时,才使用强制形式(as!
)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。
下面的例子,迭代了 library
里的每一个 MediaItem
,并打印出适当的描述。要这样做,item
需要真正作为 Movie
或 Song
的类型来使用,而不仅仅是作为 MediaItem
。为了能够在描述中使用 Movie
或 Song
的 director
或 artist
属性,这是必要的。
在这个示例中,数组中的每一个 item
可能是 Movie
或 Song
。事前你不知道每个 item
的真实类型,所以这里使用条件形式的类型转换(as?
)去检查循环里的每次下转:
for item in library {
if let movie = item as? Movie {
print("Movie: \(movie.name), dir. \(movie.director)")
} else if let song = item as? Song {
print("Song: \(song.name), by \(song.artist)")
}
}
// Movie: Casablanca, dir. Michael Curtiz
// Song: Blue Suede Shoes, by Elvis Presley
// Movie: Citizen Kane, dir. Orson Welles
// Song: The One And Only, by Chesney Hawkes
// Song: Never Gonna Give You Up, by Rick Astley
示例首先试图将 item
下转为 Movie
。因为 item
是一个 MediaItem
类型的实例,它可能是一个 Movie
;同样,它也可能是一个 Song
,或者仅仅是基类 MediaItem
。因为不确定,as?
形式在试图下转时将返回一个可选值。item as? Movie
的返回值是 Movie?
或者说“可选 Movie
”。
当向下转型为 Movie
应用在两个 Song
实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 Movie
真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“if let movie = item as? Movie
”,可以这样解读:
“尝试将 item
转为 Movie
类型。若成功,设置一个新的临时常量 movie
来存储返回的可选 Movie
中的值”
若向下转型成功,然后 movie
的属性将用于打印一个 Movie
实例的描述,包括它的导演的名字 director
。相似的原理被用来检测 Song
实例,当 Song
被找到时则打印它的描述(包含 artist
的名字)。
注意
转换没有真的改变实例或它的值。根本的实例保持不变;只是简单地把它作为它被转换成的类型来使用。