操作符 is 和 as,一个负责检查,一个负责转换。as? 优雅转换,失败可以返回 nil,as! 强制转换,失败就失败,失败就报错!
类型强转
Swift 提供 is 和 as 操作符用来检查类型和强制转换类型。
先定义几个类型。
下面是一个顶级类型。
classMediaItem{ var name: String init(name: String) { self.name = name } }
下面是两个子类。
classMovie: MediaItem{ var director: String init(name: String, director: String) { self.director = director super.init(name: name) } }
classSong: MediaItem{ var artist: String init(name: String, artist: String) { self.artist = artist super.init(name: name) } }
下面定义一个数组包含 2 个 Movie 和 3 个 Song。Swift 可以发现 Movie 和 Song 有共同的父类 MediaItem,所以 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]
此时会出现一个问题,当你遍历 library 时,每个 item 的类型将是 MediaItem,而不是 Movie 或者 Song。你需要处理它们正确的原本的类型,此时你需要检查并强转它们。
检查类型
使用 is 操作符检查类型。下面检查 library 中每个元素的类型,并对 Movie 和 Song 进行计数。
var movieCount =0 var songCount =0
for item in library { if item isMovie { movieCount +=1 } elseif item isSong { songCount +=1 } }
print("Media library contains \(movieCount) movies and \(songCount) songs") // Prints "Media library contains 2 movies and 3 songs"
for item in library { iflet movie = item as?Movie { print("Movie: \(movie.name), dir. \(movie.director)") } elseiflet 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
for thing in things { switch thing { case0asInt: print("zero as an Int") case0asDouble: print("zero as a Double") caselet someInt asInt: print("an integer value of \(someInt)") caselet someDouble asDoublewhere someDouble >0: print("a positive double value of \(someDouble)") caseisDouble: print("some other double value that I don't want to print") caselet someString asString: print("a string value of \"\(someString)\"") caselet (x, y) as (Double, Double): print("an (x, y) point at \(x), \(y)") caselet movie asMovie: print("a movie called \(movie.name), dir. \(movie.director)") caselet 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