Swift類型轉(zhuǎn)換淺析

寫在前面

類型轉(zhuǎn)換在很多編程語(yǔ)言中都會(huì)用到,比如在Objective-C中(如果你恰好用它??),你肯定經(jīng)常寫下面這種代碼:

id value;
NSDictionary *dic = (NSDictionary *)value;

當(dāng)然,這段代碼很莫名其妙,這里只是舉個(gè)簡(jiǎn)單的例子。在Swift中,類型轉(zhuǎn)換(Type Casting)的實(shí)現(xiàn)稍微有點(diǎn)不同。在Swift中,主要通過(guò)isas兩個(gè)運(yùn)算符來(lái)檢查一個(gè)對(duì)象是不是屬于某個(gè)類或者把一個(gè)對(duì)象轉(zhuǎn)成某種類。這里主要針對(duì)指針類,對(duì)于值類可以通過(guò)如下方式進(jìn)行轉(zhuǎn)換:

let hourlyRate = 19.5
let hoursWorked = 10
let totalCost = hourlyRate * Double(hoursWorked)

這里hoursWorked本來(lái)編譯器會(huì)自動(dòng)推斷為Int類型,通過(guò)Double()轉(zhuǎn)換之后就變成了Double類型。

先建一個(gè)類體系

首先建一個(gè)叫MediaItem的基類,它有一個(gè)name屬性:

class MediaItem: NSObject {

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

再建兩個(gè)子類,MovieSong,分別增加一個(gè)director屬性和artist屬性:

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

通過(guò)字面量方法創(chuàng)建一個(gè)數(shù)組,里面有兩個(gè)Movie和三個(gè)Song。因?yàn)镾wift的類檢查器可以推斷MovieSong有一個(gè)共同的父類MediaItem,所以它會(huì)斷定該數(shù)組是一個(gè)[MediaItem]類型的數(shù)組:

let library = [
            Movie(name: "KF_Movie_1", director: "Wudao"),
            Song(name: "KF_Song_1", artist: "Qingge"),
            Movie(name: "KF_Movie_2", director: "Hetu"),
            Song(name: "KF_Song_2", artist: "Shantai"),
            Song(name: "KF_Song_3", artist: "Jianjia"),
]

這個(gè)library里的元素明顯是MovieSong,但是如果循環(huán)瀏覽,會(huì)發(fā)現(xiàn)它返回的類型是MediaItem,并不是MovieSong。為了用到每個(gè)元素它實(shí)際的類型的屬性、方法,這時(shí)候我們就需要檢查或者轉(zhuǎn)換它了。

檢查類型

定義兩個(gè)變量movieCountsongCount,利用is檢查元素的類型,是Movie的話,movieCount加1,是Song的話,則songCount加1。

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

運(yùn)行結(jié)果:

Media library contains 2 movies and 3 songs

顯然通過(guò)is可以判斷出數(shù)組里有2個(gè)Movie,三個(gè)Song。

類型轉(zhuǎn)換

Swift中類型轉(zhuǎn)換有兩個(gè)類型轉(zhuǎn)換符:as?as!。as?返回的是一個(gè)可選值,可能為nil,as!返回的是一個(gè)展開的具體的
值。

Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.

Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type.

簡(jiǎn)單的說(shuō),如果你明確知道要轉(zhuǎn)換類型的那個(gè)元素真正類型,確保能轉(zhuǎn)換成功,這時(shí)候就用as!,否則,用as?。

在librar這個(gè)例子,我想分別打印出movie和song的相關(guān)信息,就得用到類型轉(zhuǎn)換符,這里因?yàn)樵乜赡苁?em>Movie,也可能是Song,類型不能確定,所以用as?轉(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)")
    }
}

運(yùn)行結(jié)果:

Movie: KF_Movie_1, dir.Wudao
Song: KF_Song_1, by Qingge
Movie: KF_Movie_2, dir.Hetu
Song: KF_Song_2, by Shantai
Song: KF_Song_3, by Jianjia

這個(gè)例子牽涉到了可選值(optional)的展開方式,這里不展開細(xì)講,有問(wèn)題可以給我發(fā)郵件或直接在評(píng)論區(qū)提出。

Any和AnyObject的類型轉(zhuǎn)換

Swift中,定義了兩個(gè)特殊的類名來(lái)替代那些沒有具體指明類型的類:

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

在開發(fā)中,我們有時(shí)候會(huì)獲得一個(gè)[AnyObject]類型的數(shù)組,或者一個(gè)元素可以為任何類型的數(shù)組,但事實(shí)上我們很確定這個(gè)數(shù)組的元素是什么類型,這種情況我們可以用as!把AnyObject轉(zhuǎn)換成更具體的那個(gè)類。如下,先定義一個(gè)[AnyObject]類型的數(shù)組:

let someObjects: [AnyObject] = [
    Movie(name: "KF_Movie_3", director: "Guoshi"),
    Movie(name: "KF_Movie_4", director: "Wushuang"),
    Movie(name: "KF_Movie_5", director: "Fenglei")
]

在這里,我們知道數(shù)組的元素都是Movie,所以用as!轉(zhuǎn)換:

for object in someObjects {
    let movie = object as! Movie
    print("Movie: \(movie.name), dir. \(movie.director)")
}

還有一種更簡(jiǎn)便的寫法,直接轉(zhuǎn)換數(shù)組:

for movie in someObjects as! [Movie] {
    print("Movie: \(movie.name), dir. \(movie.director)")
}

運(yùn)行結(jié)果:

Movie: KF_Movie_3, dir. Guoshi
Movie: KF_Movie_4, dir. Wushuang
Movie: KF_Movie_5, dir. Fenglei

Any轉(zhuǎn)換,先定義一個(gè)[Any]類型數(shù)組,其實(shí)就是包含任何類型元素的數(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: "KF_Movie_6", director: "kefan"))
things.append({ (name: String) -> String in "Hello, \(name)" })

可以通過(guò)isas來(lái)判斷元素的類型進(jì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")
    }
}

運(yùn)行結(jié)果:

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 KF_Movie_6, dir. kefan
Hello, Michael

寫在最后

本文算是Type Casting的一個(gè)粗糙的翻譯吧,可能有些地方不是那么準(zhǔn)確,請(qǐng)多多請(qǐng)教。

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 132.轉(zhuǎn)換錯(cuò)誤成可選值 通過(guò)轉(zhuǎn)換錯(cuò)誤成一個(gè)可選值,你可以使用 try? 來(lái)處理錯(cuò)誤。當(dāng)執(zhí)行try?表達(dá)式時(shí),如果...
    無(wú)灃閱讀 1,427評(píng)論 0 3
  • 類型轉(zhuǎn)換是一種檢查實(shí)例類型的方法,或者將該實(shí)例視為來(lái)自其自身類層次結(jié)構(gòu)中的其他地方的不同超類或子類。Swift中的...
    Joker_King閱讀 2,633評(píng)論 0 0
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile麗語(yǔ)閱讀 4,080評(píng)論 0 6
  • 作者:潘知常,南京大學(xué)新聞傳播學(xué)院教授、博士生導(dǎo)師摘自:《東南學(xué)術(shù)》2017年第1期,原題為“無(wú)神時(shí)代:審美何為?...
    你他娘的真是個(gè)天才閱讀 740評(píng)論 0 0
  • 做京東第二個(gè)月了,今天才知道我接手的店鋪已經(jīng)有兩年多了,上兩個(gè)星期剛從pop轉(zhuǎn)sop,苦于初期流量有限,每天五六百...
    蔣春濤閱讀 156評(píng)論 0 0

友情鏈接更多精彩內(nèi)容