【Swift 3.1】19 - 類型轉(zhuǎn)換 (Type Casting)
自從蘋果2014年發(fā)布Swift,到現(xiàn)在已經(jīng)兩年多了,而Swift也來到了3.1版本。去年利用工作之余,共花了兩個多月的時間把官方的Swift編程指南看完。現(xiàn)在整理一下筆記,回顧一下以前的知識。有需要的同學(xué)可以去看官方文檔>>。
類型轉(zhuǎn)換是用來檢查實(shí)例的類型,或在繼承鏈中把實(shí)例作為不同的父類或子類的一種方法。
Swift中的類型轉(zhuǎn)換用is
和as
來實(shí)現(xiàn)。
為類型轉(zhuǎn)換定義一個類的層次結(jié)構(gòu) (Defining a Class Hierarchy for Type Casting)
第一個類是MediaItem
。假設(shè)所有的媒體項目,包括電影和音樂,并且有名字:
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
第二個類是MediaItem
的子類Movie
。第三個也是MediaItem
的子類:
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)
}
}
最后創(chuàng)建了一個library
數(shù)組,包含了兩個Movie
實(shí)例和三個Song
實(shí)例。Swift根據(jù)字面值推斷出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]
雖然這個數(shù)組裝的是Movie
和Song
實(shí)例,但如果遍歷這個數(shù)組,取出來的元素是MediaItem
類型,而不是Movie
和Song
類型。為了使用他們的真實(shí)類型,我們需要檢查他們的類型,或者向下轉(zhuǎn)型。
檢查類型 (Checking Type)
使用is
來檢查一個實(shí)例是否是一個子類類型。如果是一個子類類型,返回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"
向下轉(zhuǎn)型 (Downcasting)
一個類型的常量或變量實(shí)際上可能是子類的實(shí)例類型,我們可以使用as?
或者as!
來向下轉(zhuǎn)型到子類類型。
因為向下轉(zhuǎn)型可能會失敗,所以轉(zhuǎn)型運(yùn)算符有兩種類型。as?
返回你想轉(zhuǎn)到的那個類型的可選類型;而as!
如果轉(zhuǎn)型成功,返回你想轉(zhuǎn)到的那個類型,轉(zhuǎn)型失敗將會報錯。
如果不確定是否能轉(zhuǎn)型成功,使用as?
;如果能確定轉(zhuǎn)型成功,使用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)")
}
}
注意:轉(zhuǎn)型實(shí)際上不會修改實(shí)例或者改變它的值,在底層中,還是同一個實(shí)例。
Any和AnyObject的類型轉(zhuǎn)換 (Type Casting for Any and AnyObject)
Swift提供了兩種不確定的類型:
-
Any
可以代表任何類型的實(shí)例,包括方法類型 -
AnyObject
代表任何class類型的實(shí)例
下面是一個例子:
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)" })
向下轉(zhuǎn)型:
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會給你一個警告。如果確實(shí)需要把可選類型的值作為一個Any
類型的值,可以使用as
來明確地轉(zhuǎn)為Any
類型:
let optionalNumber: Int? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning
第十九部分完。下個部分:【Swift 3.1】20 - 嵌套類型 (Nested Types)
如果有錯誤的地方,歡迎指正!謝謝!