- 检查实例的类型;
- 将实例看作其自身类层次结构中其他不同的超类或子类;
- 类型转换可以检查类型是否符合某协议;
- Swift中的类型转换用
is
和as
操作符来实现;
1. 定义类型转换的类层次结构
可以使用具有类和子类层次结构的类型转换来检查特定类实例的类型,并将该实例转换到相同层次结构中的另一个类。
定义一个基类MediaItem
:
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
定义基类MediaItem
的两个子类---Movie
和Song
:
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
定义一个数组library
,数组中的元素类型是MediaItem
:
let library = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Welles"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// the type of "library" is inferred to be [MediaItem]
2.检测类型
使用类型检查操作符is
检查实例是否属于某个子类类型。如果实例属于该子类类型,类型检查操作符返回true;如果不是,则返回false。
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
}
print("Media library contains \(movieCount) movies and \(songCount) songs")
// Prints "Media library contains 2 movies and 3 songs"
3.类型转换
某个类类型的常量或变量实际上可能引用子类的实例。这种情况下,可以尝试使用类型转换操作符as ?
或as !
。
-
as?
返回要转换类型的可选值;当不确定类转换是否成功时,使用该条件类型转换; -
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
强制类型转换实际上并不会修改实例或更改其值。底层实例保持不变;它被简单地当作一个已被转换类型的实例来处理和访问。
4.Any
和AnyObject
的类型转换
Swift提供了两种用于处理非特定类型的特殊类型:
-
Any
可以表示任何类型的实例,包括函数类型。 -
AnyObject
可以表示任何类类型的实例。
var things = [Any]()
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
for thing in things {
switch thing {
case 0 as Int:
print("zero as an Int")
case 0 as Double:
print("zero as a Double")
case let someInt as Int:
print("an integer value of \(someInt)")
case let someDouble as Double where someDouble > 0:
print("a positive double value of \(someDouble)")
case is Double:
print("some other double value that I don't want to print")
case let someString as String:
print("a string value of \"\(someString)\"")
case let (x, y) as (Double, Double):
print("an (x, y) point at \(x), \(y)")
case let movie as Movie:
print("a movie called \(movie.name), dir. \(movie.director)")
case let stringConverter as (String) -> String:
print(stringConverter("Michael"))
default:
print("something else")
}
}
// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called Ghostbusters, dir. Ivan Reitman
// Hello, Michael
-
Any
表示任何类型的值,包括可选类型。如果使用一个可选的值,其中预期值类型为Any, 则Swift会产生警告。如果确实需要使用可选值作为任意值,那么可以使用as
操作符将可选值显式转换为任意值,如下所示。
let optionalNumber: Int? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning