类型检查在@H_502_2@ Swift @H_502_2@中使用@H_502_2@is@H_502_2@和@H_502_2@ as@H_502_2@操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。@H_502_2@
定义一个类层次作为例子@H_502_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]
library@H_502_2@的储存的是@H_502_2@Movie@H_502_2@和@H_502_2@Song@H_502_2@的实例@H_502_2@,@H_502_2@若你迭代它@H_502_2@,@H_502_2@则取出的会是其父类@H_502_2@MediaItem@H_502_2@类型@H_502_2@,@H_502_2@而不是@H_502_2@Movie@H_502_2@和@H_502_2@Song@H_502_2@类型。为了让它们作为它们本来的类型工作,你需要检查它们的类型或者向下转换它们的类型到其它类型。@H_502_2@
通过操作符@H_502_2@is@H_502_2@来检查一个实例是否属于特定的子类型@H_502_2@,@H_502_2@返回@H_502_2@true@H_502_2@则属于@H_502_2@
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"
向下转型@H_502_2@
通过类型检查操作符@H_502_2@as@H_502_2@可向下转型@H_502_2@.@H_502_2@但是由于向下转型可能会失败@H_502_2@
故有两种形式①可选形式@H_502_2@as? @H_502_2@②强制形式@H_502_2@as!@H_502_2@
当你确定转型一定会成功的时候使用@H_502_2@as!@H_502_2@@H_502_2@
for item in library { //由于item是一个MediaItem类型的实例,它可能是一个Movie,故使用as? 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)") } }
Any@H_502_2@和@H_502_2@AnyObject@H_502_2@类型检查@H_502_2@
Swift@H_502_2@为不确定类型提供了两种特殊类型别名:@H_502_2@
①@H_502_2@AnyObject@H_502_2@可以代表任何@H_502_2@class@H_502_2@类型的实例。@H_502_2@
②@H_502_2@Any@H_502_2@可以表示任何类型,除了方法类型(@H_502_2@function types@H_502_2@)。@H_502_2@
注意:@H_502_2@只有当你明确的需要它的行为和功能时才使用@H_502_2@Any@H_502_2@和@H_502_2@AnyObject@H_502_2@。在你的代码里使用你期望的明确的类型总是更好的。@H_502_2@
let someObjects: [AnyObject] = [ Movie(name: "2001: A Space Odyssey",director: "Stanley Kubrick"),Movie(name: "Moon",director: "Duncan Jones"),Movie(name: "Alien",director: "Ridley Scott") ]
由于这个数组中只包含@H_502_2@Movie@H_502_2@实例@H_502_2@,@H_502_2@所以你可以直接使用@H_502_2@as!@H_502_2@来进行强制解包@H_502_2@
for object in someObjects { let movie = object as! Movie }
或者直接将@H_502_2@[AnyObject]@H_502_2@强转成@H_502_2@[Movie]@H_502_2@
for movie in someObjects as! [Movie] { println("Movie: '\(movie.name)',dir. \(movie.director)") }
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@H_502_2@中包含@H_502_2@2@H_502_2@个@H_502_2@Int,2@H_502_2@个@H_502_2@Double,1@H_502_2@个@H_502_2@String,1@H_502_2@个元组@H_502_2@ (Double,Double),@H_502_2@一个@H_502_2@Movie@H_502_2@对象@H_502_2@
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)") 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
类型嵌套@H_502_2@
一个类型中嵌套另一个类型,将需要嵌套的类型的定义写在被嵌套类型的区域@H_502_2@{}@H_502_2@内,而且可以根据需要定义多级嵌套@H_502_2@
struct BlackjackCard { // 嵌套定义枚举型Suit enum Suit: Character { case Spades = "♠",Hearts = "♡",Diamonds = "♢",Clubs = "♣" } // 嵌套定义枚举型Rank enum Rank: Int { case Two = 2,Three,Four,Five,Six,Seven,Eight,Nine,Ten case Jack,Queen,King,Ace struct Values { let first: Int,second: Int? } var values: Values { switch self { case .Ace: return Values(first: 1,second: 11) case .Jack,.Queen,.King: return Values(first: 10,second: nil) default: return Values(first: self.toRaw(),second: nil) } } } // BlackjackCard 的属性和方法 let rank: Rank,suit: Suit var description: String { var output = "suit is \(suit.toRaw())," output += " value is \(rank.values.first)" if let second = rank.values.second { output += " or \(second)" } return output } }
枚举型的@H_502_2@ Suit@H_502_2@ 用来描述扑克牌的四种花色,并分别用一个@H_502_2@ Character@H_502_2@ 类型的值代表花色符号。@H_502_2@
枚举型的@H_502_2@Rank@H_502_2@用来描述扑克牌从@H_502_2@Ace~10,J,Q,K,13@H_502_2@张牌,并分别用一个@H_502_2@Int@H_502_2@类型的值表示牌的面值。@H_502_2@(@H_502_2@这个@H_502_2@Int@H_502_2@类型的值不适用于@H_502_2@Ace,K@H_502_2@的牌@H_502_2@)@H_502_2@。@H_502_2@
举型@H_502_2@Rank@H_502_2@在自己内部定义了一个嵌套结构体@H_502_2@Values@H_502_2@。这个结构体包含两个变量,只有@H_502_2@Ace@H_502_2@有两个数值,其余牌都只有一个数值。结构体@H_502_2@Values@H_502_2@中定义的两个属性:@H_502_2@first,@H_502_2@为@H_502_2@Int ; second,@H_502_2@为@H_502_2@ Int?,@H_502_2@或@H_502_2@ “optional Int”@H_502_2@
Rank@H_502_2@定义了一个计算属性@H_502_2@values@H_502_2@,这个计算属性会根据牌的面值,用适当的数值去初始化@H_502_2@Values@H_502_2@实例,并赋值给@H_502_2@values@H_502_2@。对于@H_502_2@J,Ace@H_502_2@会使用特殊数值,对于数字面值的牌使用@H_502_2@Int@H_502_2@类型的值。@H_502_2@
BlackjackCard@H_502_2@结构体自身有两个属性@H_502_2@—rank@H_502_2@与@H_502_2@suit@H_502_2@,也同样定义了一个计算属性@H_502_2@description@H_502_2@,@H_502_2@description@H_502_2@属性用@H_502_2@rank@H_502_2@和@H_502_2@suit@H_502_2@的中内容来构建对这张扑克牌名字和数值的描述,并用可选类型@H_502_2@second@H_502_2@来检查是否存在第二个值,若存在,则在原有的描述中增加对第二数值的描述。@H_502_2@
因为@H_502_2@BlackjackCard@H_502_2@是一个没有自定义构造函数的结构体,在@H_502_2@Memberwise Initializers for Structure Types@H_502_2@中知道结构体有默认的成员构造函数,所以你可以用默认的@H_502_2@initializer@H_502_2@去初始化新的常量@H_502_2@theAceOfSpades:@H_502_2@
let theAceOfSpades = BlackjackCard(rank: .Ace,suit: .Spades) println("theAceOfSpades: \(theAceOfSpades.description)") // 打印出 "theAceOfSpades: suit is ♠,value is 1 or 11"
尽管@H_502_2@Rank@H_502_2@和@H_502_2@Suit@H_502_2@嵌套在@H_502_2@BlackjackCard@H_502_2@中,但仍可被引用,所以在初始化实例时能够通过枚举类型中的成员名称单独引用。在上面的例子中@H_502_2@description@H_502_2@属性能正确得输出对@H_502_2@Ace@H_502_2@牌有@H_502_2@1@H_502_2@和@H_502_2@11@H_502_2@两个值。@H_502_2@
类型嵌套的引用
在外部对嵌套类型的引用,以被嵌套类型的名字为前缀,加上所要引用的属性名:@H_502_2@
let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw() // 红心的符号 为 "♡"