十七、类型绑定 Type Casting
1. 概述
Type Casting 的作用:
- 1)expression is type,is 检查某个实例的类型。
- 2)expression as type,as 在编译阶段将某个实例的类型绑定为其他类型来访问,并且总是成功。
- 3)expression as? type,as? 返回指定类型的可选值。在运行时,如果绑定成功,expression 会被打包为一个可选值返回,如果绑定失败,返回值是nil
- 4)expression as! type,as! 强制转换 expression 为指定类型,as! 返回的不是可选值,如果绑定失败了,会触发运行时错误。x as! T 与 (x as? T)!是等价的
- 5)检查某种类型是否实现了协议的方法。
2. 引例,定义三个类:
class MediaItem { var name: String init(name: String) { self.name = name } }
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) } }
定义一个数组:
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.1 检查实例的类型 Checking Type
使用类型检查操作符(type check operator) is 判断一个实例是否是子类类型。如果是子类类型返回 true,否则返回 false。
遍历上面的数组:
var movieCount = 0 var songCount = 0 for item in library { if item is Movie { ++movieCount } else if item is Song { ++songCount } } println("Media library contains \(movieCount) movies and \(songCount) songs") // prints "Media library contains 2 movies and 3 songs"
2.2 向下绑定 Downcasting
一个类实例有时要当做它的子类实例来使用,使用类型绑定操作符(type cast operator) as 来向下绑定到子类类型。
如果你不确定转换是否会成功,使用可选值形式 as? ,如果失败,返回 nil 。
for item in library { if let movie = item as? Movie { println("Movie: '\(movie.name)', dir. \(movie.director)") } else if let song = item as? Song { println("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
注意:类型绑定并没有真的修改实例,仅仅只是把它当做它所绑定的类型来对待和访问。
3. 绑定为Any和AnyObject类型 Type Casting for Any and AnyObject
Swift为一些不明确的类型提供了两个特殊的类型别名:
- 1)AnyObject 可以表示任何类类型的实例(对象类型)。
- 2)Any 可以表示任何类型,包括函数类型。
3.1 AnyObject 类型
比如:
let someObjects: [AnyObject] = [ Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), Movie(name: "Moon", director: "Duncan Jones"), Movie(name: "Alien", director: "Ridley Scott") ]
因为数组中都是Movie的实例类型(对象类型),我们可以将他们向下绑定直接拆包为非可选的Movie类型
for object in someObjects { let movie = object as Movie println("Movie: '\(movie.name)', dir. \(movie.director)") } // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick // Movie: 'Moon', dir. Duncan Jones // Movie: 'Alien', dir. Ridley Scott
也可以使用更简洁的方式——将数组 someObjects的[AnyObject]类型 向下绑定为 [Movie]类型:
for movie in someObjects as [Movie] { println("Movie: '\(movie.name)', dir. \(movie.director)") } // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick // Movie: 'Moon', dir. Duncan Jones // Movie: 'Alien', dir. Ridley Scott
3.2 Any 类型
比如:
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: println("zero as an Int") case 0 as Double: println("zero as a Double") case let someInt as Int: println("an integer value of \(someInt)") case let someDouble as Double where someDouble > 0: println("a positive double value of \(someDouble)") case is Double: println("some other double value that I don't want to print") case let someString as String: println("a string value of \"\(someString)\"") case let (x, y) as (Double, Double): println("an (x, y) point at \(x), \(y)") case let movie as Movie: println("a movie called '\(movie.name)', dir. \(movie.director)") case let stringConverter as String -> String: println(stringConverter("Michael")) default: println("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
注意:在上面的代码中使用的是强制绑定as而不是可选的绑定as?,因为在在switch的case语句中使用强制的as永远是安全的。