鍍金池/ 教程/ iOS/ 類型轉(zhuǎn)換
特性(Attributes)
Access Control 權(quán)限控制的黑與白
基本運算符(Basic Operators)
基礎(chǔ)部分(The Basics)
閉包(Closures)
擴展
泛型參數(shù)(Generic Parameters and Arguments)
訪問控制和 protected
語句(Statements)
模式(Patterns)
WWDC 里面的那個“大炮打氣球”
關(guān)于語言參考(About the Language Reference)
語法總結(jié)(Summary of the Grammar)
嵌套類型
類型(Types)
Swift 初見(A Swift Tour)
泛型
枚舉(Enumerations)
高級運算符
繼承
析構(gòu)過程
關(guān)于 Swift(About Swift)
訪問控制
類和結(jié)構(gòu)體
內(nèi)存安全
Swift 與 C 語言指針友好合作
協(xié)議
屬性(Properties)
可選類型完美解決占位問題
錯誤處理
字符串和字符(Strings and Characters)
聲明(Declarations)
自動引用計數(shù)
Swift 里的值類型與引用類型
表達式(Expressions)
Swift 文檔修訂歷史
造個類型不是夢-白話 Swift 類型創(chuàng)建
歡迎使用 Swift
詞法結(jié)構(gòu)(Lexical Structure)
集合類型(Collection Types)
下標
方法(Methods)
可選鏈式調(diào)用
版本兼容性
類型轉(zhuǎn)換
構(gòu)造過程
The Swift Programming Language 中文版
函數(shù)(Functions)
Swift 教程
控制流(Control Flow)

類型轉(zhuǎn)換


1.0 翻譯:xiehurricane 校對:happyming

2.0 翻譯+校對:yangsiy

2.1 校對:shanks,2015-11-01

2.2 翻譯+校對:SketchK 2016-05-16 3.0.1,shanks,2016-11-13

4.0 校對:kemchenj 2017-09-21

4.1 翻譯+校對:mylittleswift

本頁包含內(nèi)容:

類型轉(zhuǎn)換可以判斷實例的類型,也可以將實例看做是其父類或者子類的實例。

類型轉(zhuǎn)換在 Swift 中使用 isas 操作符實現(xiàn)。這兩個操作符提供了一種簡單達意的方式去檢查值的類型或者轉(zhuǎn)換它的類型。

你也可以用它來檢查一個類型是否實現(xiàn)了某個協(xié)議,就像在檢驗協(xié)議的一致性部分講述的一樣。

為類型轉(zhuǎn)換定義類層次

你可以將類型轉(zhuǎn)換用在類和子類的層次結(jié)構(gòu)上,檢查特定類實例的類型并且轉(zhuǎn)換這個類實例的類型成為這個層次結(jié)構(gòu)中的其他類型。下面的三個代碼段定義了一個類層次和一個包含了這些類實例的數(shù)組,作為類型轉(zhuǎn)換的例子。

第一個代碼片段定義了一個新的基類 MediaItem。這個類為任何出現(xiàn)在數(shù)字媒體庫的媒體項提供基礎(chǔ)功能。特別的,它聲明了一個 String 類型的 name 屬性,和一個 init(name:) 初始化器。(假定所有的媒體項都有個名稱。)

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

下一個代碼段定義了 MediaItem 的兩個子類。第一個子類 Movie 封裝了與電影相關(guān)的額外信息,在父類(或者說基類)的基礎(chǔ)上增加了一個 director(導演)屬性,和相應(yīng)的初始化器。第二個子類 Song,在父類的基礎(chǔ)上增加了一個 artist(藝術(shù)家)屬性,和相應(yīng)的初始化器:

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)建了一個數(shù)組常量 library,包含兩個 Movie 實例和三個 Song 實例。library 的類型是在它被初始化時根據(jù)它數(shù)組中所包含的內(nèi)容推斷來的。Swift 的類型檢測器能夠推斷出 MovieSong 有共同的父類 MediaItem,所以它推斷出 [MediaItem] 類作為 library 的類型:

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")
]
// 數(shù)組 library 的類型被推斷為 [MediaItem]

在幕后 library 里存儲的媒體項依然是 MovieSong 類型的。但是,若你迭代它,依次取出的實例會是 MediaItem 類型的,而不是 MovieSong 類型。為了讓它們作為原本的類型工作,你需要檢查它們的類型或者向下轉(zhuǎn)換它們到其它類型,就像下面描述的一樣。

檢查類型

類型檢查操作符is)來檢查一個實例是否屬于特定子類型。若實例屬于那個子類型,類型檢查操作符返回 true,否則返回 false。

下面的例子定義了兩個變量,movieCountsongCount,用來計算數(shù)組 libraryMovieSong 類型的實例數(shù)量:

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")
// 打印 “Media library contains 2 movies and 3 songs”

示例迭代了數(shù)組 library 中的所有項。每一次,for-in 循環(huán)設(shè)置 item 為數(shù)組中的下一個 MediaItem。

若當前 MediaItem 是一個 Movie 類型的實例,item is Movie 返回 true,否則返回 false。同樣的,item is Song 檢查 item 是否為 Song 類型的實例。在循環(huán)結(jié)束后,movieCountsongCount 的值就是被找到的屬于各自類型的實例的數(shù)量。

向下轉(zhuǎn)型

某類型的一個常量或變量可能在幕后實際上屬于一個子類。當確定是這種情況時,你可以嘗試向下轉(zhuǎn)到它的子類型,用類型轉(zhuǎn)換操作符as?as!)。

因為向下轉(zhuǎn)型可能會失敗,類型轉(zhuǎn)型操作符帶有兩種不同形式。條件形式 as? 返回一個你試圖向下轉(zhuǎn)成的類型的可選值。強制形式 as! 把試圖向下轉(zhuǎn)型和強制解包轉(zhuǎn)換結(jié)果結(jié)合為一個操作。

當你不確定向下轉(zhuǎn)型可以成功時,用類型轉(zhuǎn)換的條件形式(as?)。條件形式的類型轉(zhuǎn)換總是返回一個可選值,并且若下轉(zhuǎn)是不可能的,可選值將是 nil。這使你能夠檢查向下轉(zhuǎn)型是否成功。

只有你可以確定向下轉(zhuǎn)型一定會成功時,才使用強制形式(as!)。當你試圖向下轉(zhuǎn)型為一個不正確的類型時,強制形式的類型轉(zhuǎn)換會觸發(fā)一個運行時錯誤。

下面的例子,迭代了 library 里的每一個 MediaItem,并打印出適當?shù)拿枋?。要這樣做,item 需要真正作為 MovieSong 的類型來使用,而不僅僅是作為 MediaItem。為了能夠在描述中使用 MovieSongdirectorartist 屬性,這是必要的。

在這個示例中,數(shù)組中的每一個 item 可能是 MovieSong。事前你不知道每個 item 的真實類型,所以這里使用條件形式的類型轉(zhuǎn)換(as?)去檢查循環(huán)里的每次下轉(zhuǎn):

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

示例首先試圖將 item 下轉(zhuǎn)為 Movie。因為 item 是一個 MediaItem 類型的實例,它可能是一個 Movie;同樣,它也可能是一個 Song,或者僅僅是基類 MediaItem。因為不確定,as? 形式在試圖下轉(zhuǎn)時將返回一個可選值。item as? Movie 的返回值是 Movie? 或者說“可選 Movie”。

當向下轉(zhuǎn)型為 Movie 應(yīng)用在兩個 Song 實例時將會失敗。為了處理這種情況,上面的例子使用了可選綁定(optional binding)來檢查可選 Movie 真的包含一個值(這個是為了判斷下轉(zhuǎn)是否成功。)可選綁定是這樣寫的“if let movie = item as? Movie”,可以這樣解讀:

“嘗試將 item 轉(zhuǎn)為 Movie 類型。若成功,設(shè)置一個新的臨時常量 movie 來存儲返回的可選 Movie 中的值”

若向下轉(zhuǎn)型成功,然后 movie 的屬性將用于打印一個 Movie 實例的描述,包括它的導演的名字 director。相似的原理被用來檢測 Song 實例,當 Song 被找到時則打印它的描述(包含 artist 的名字)。

注意

轉(zhuǎn)換沒有真的改變實例或它的值。根本的實例保持不變;只是簡單地把它作為它被轉(zhuǎn)換成的類型來使用。

AnyAnyObject 的類型轉(zhuǎn)換

Swift 為不確定類型提供了兩種特殊的類型別名:

  • Any 可以表示任何類型,包括函數(shù)類型。
  • AnyObject 可以表示任何類類型的實例。

只有當你確實需要它們的行為和功能時才使用 AnyAnyObject。當你期望你的代碼可以工作,最好還是要確定類型。

這里有個示例,使用 Any 類型來和混合的不同類型一起工作,包括函數(shù)類型和非類類型。它創(chuàng)建了一個可以存儲 Any 類型的數(shù)組 things

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)" })

things 數(shù)組包含兩個 Int 值,兩個 Double 值,一個 String 值,一個元組 (Double, Double),一個 Movie 實例“Ghostbusters”,以及一個接受 String 值并返回另一個 String 值的閉包表達式。

你可以在 switch 表達式的 case 中使用 isas 操作符來找出只知道是 AnyAnyObject 類型的常量或變量的具體類型。下面的示例迭代 things 數(shù)組中的每一項,并用 switch 語句查找每一項的類型。有幾個 switch 語句的 case 綁定它們匹配到的值到一個指定類型的常量,從而可以打印這些值:

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 類型可以表示所有類型的值,包括可選類型。Swift 會在你用 Any 類型來表示一個可選值的時候,給你一個警告。如果你確實想使用 Any 類型來承載可選值,你可以使用 as 操作符顯式轉(zhuǎn)換為 Any,如下所示:

let optionalNumber: Int? = 3
things.append(optionalNumber)        // 警告
things.append(optionalNumber as Any) // 沒有警告
上一篇:構(gòu)造過程下一篇:協(xié)議