Swift 型別轉換

Swift 語言型別轉換可以判斷例項的型別。也可以用於檢測例項型別是否屬於其父類或者子類的例項。

Swift 中型別轉換使用 is 和 as 操作符實現,is 用於檢測值的型別,as 用於轉換型別。

型別轉換也可以用來檢查一個類是否實現了某個協議。


定義一個類層次

以下定義了三個類:Subjects、Chemistry、Maths,Chemistry 和 Maths 繼承了 Subjects。

程式碼如下:

class Subjects {
    var physics: String
    init(physics: String) {
        self.physics = physics
    }
}

class Chemistry: Subjects {
    var equations: String
    init(physics: String, equations: String) {
        self.equations = equations
        super.init(physics: physics)
    }
}

class Maths: Subjects {
    var formulae: String
    init(physics: String, formulae: String) {
        self.formulae = formulae
        super.init(physics: physics)
    }
}

let sa = [
    Chemistry(physics: "固體物理", equations: "赫茲"),
    Maths(physics: "流體動力學", formulae: "千兆赫")]


let samplechem = Chemistry(physics: "固體物理", equations: "赫茲")
print("例項物理學是: \(samplechem.physics)")
print("例項方程式: \(samplechem.equations)")


let samplemaths = Maths(physics: "流體動力學", formulae: "千兆赫")
print("例項物理學是: \(samplemaths.physics)")
print("例項公式是: \(samplemaths.formulae)")

以上程式執行輸出結果為:

例項物理學是: 固體物理
例項方程式: 赫茲
例項物理學是: 流體動力學
例項公式是: 千兆赫

檢查型別

型別轉換用於檢測例項型別是否屬於特定的例項型別。

你可以將它用在類和子類的層次結構上,檢查特定類例項的型別並且轉換這個類例項的型別成為這個層次結構中的其他型別。

型別檢查使用 is 關鍵字。

操作符 is 來檢查一個例項是否屬於特定子型別。若例項屬於那個子型別,型別檢查操作符返回 true,否則返回 false。

class Subjects {
    var physics: String
    init(physics: String) {
        self.physics = physics
    }
}

class Chemistry: Subjects {
    var equations: String
    init(physics: String, equations: String) {
        self.equations = equations
        super.init(physics: physics)
    }
}

class Maths: Subjects {
    var formulae: String
    init(physics: String, formulae: String) {
        self.formulae = formulae
        super.init(physics: physics)
    }
}

let sa = [
    Chemistry(physics: "固體物理", equations: "赫茲"),
    Maths(physics: "流體動力學", formulae: "千兆赫"),
    Chemistry(physics: "熱物理學", equations: "分貝"),
    Maths(physics: "天體物理學", formulae: "兆赫"),
    Maths(physics: "微分方程", formulae: "餘弦級數")]


let samplechem = Chemistry(physics: "固體物理", equations: "赫茲")
print("例項物理學是: \(samplechem.physics)")
print("例項方程式: \(samplechem.equations)")


let samplemaths = Maths(physics: "流體動力學", formulae: "千兆赫")
print("例項物理學是: \(samplemaths.physics)")
print("例項公式是: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0
for item in sa {
    // 如果是一個 Chemistry 型別的例項,返回 true,相反返回 false。
    if item is Chemistry {
        ++chemCount
    } else if item is Maths {
        ++mathsCount
    }
}

print("化學科目包含 \(chemCount) 個主題,數學包含 \(mathsCount) 個主題")

以上程式執行輸出結果為:

例項物理學是: 固體物理
例項方程式: 赫茲
例項物理學是: 流體動力學
例項公式是: 千兆赫
化學科目包含 2 個主題,數學包含 3 個主題

向下轉型

向下轉型,用型別轉換操作符(as? 或 as!)

當你不確定向下轉型可以成功時,用型別轉換的條件形式(as?)。條件形式的型別轉換總是返回一個可選值(optional value),並且若下轉是不可能的,可選值將是 nil。

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

class Subjects {
    var physics: String
    init(physics: String) {
        self.physics = physics
    }
}

class Chemistry: Subjects {
    var equations: String
    init(physics: String, equations: String) {
        self.equations = equations
        super.init(physics: physics)
    }
}

class Maths: Subjects {
    var formulae: String
    init(physics: String, formulae: String) {
        self.formulae = formulae
        super.init(physics: physics)
    }
}

let sa = [
    Chemistry(physics: "固體物理", equations: "赫茲"),
    Maths(physics: "流體動力學", formulae: "千兆赫"),
    Chemistry(physics: "熱物理學", equations: "分貝"),
    Maths(physics: "天體物理學", formulae: "兆赫"),
    Maths(physics: "微分方程", formulae: "餘弦級數")]


let samplechem = Chemistry(physics: "固體物理", equations: "赫茲")
print("例項物理學是: \(samplechem.physics)")
print("例項方程式: \(samplechem.equations)")


let samplemaths = Maths(physics: "流體動力學", formulae: "千兆赫")
print("例項物理學是: \(samplemaths.physics)")
print("例項公式是: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in sa {
    // 型別轉換的條件形式
    if let show = item as? Chemistry {
        print("化學主題是: '\(show.physics)', \(show.equations)")
        // 強制形式
    } else if let example = item as? Maths {
        print("數學主題是: '\(example.physics)',  \(example.formulae)")
    }
}

以上程式執行輸出結果為:

例項物理學是: 固體物理
例項方程式: 赫茲
例項物理學是: 流體動力學
例項公式是: 千兆赫
化學主題是: '固體物理', 赫茲
數學主題是: '流體動力學',  千兆赫
化學主題是: '熱物理學', 分貝
數學主題是: '天體物理學',  兆赫
數學主題是: '微分方程',  餘弦級數

Any和AnyObject的型別轉換

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

  • AnyObject可以代表任何class型別的例項。
  • Any可以表示任何型別,包括方法型別(function types)。

注意:
只有當你明確的需要它的行為和功能時才使用AnyAnyObject。在你的程式碼裡使用你期望的明確的型別總是更好的。

Any 例項

class Subjects {
    var physics: String
    init(physics: String) {
        self.physics = physics
    }
}

class Chemistry: Subjects {
    var equations: String
    init(physics: String, equations: String) {
        self.equations = equations
        super.init(physics: physics)
    }
}

class Maths: Subjects {
    var formulae: String
    init(physics: String, formulae: String) {
        self.formulae = formulae
        super.init(physics: physics)
    }
}

let sa = [
    Chemistry(physics: "固體物理", equations: "赫茲"),
    Maths(physics: "流體動力學", formulae: "千兆赫"),
    Chemistry(physics: "熱物理學", equations: "分貝"),
    Maths(physics: "天體物理學", formulae: "兆赫"),
    Maths(physics: "微分方程", formulae: "餘弦級數")]


let samplechem = Chemistry(physics: "固體物理", equations: "赫茲")
print("例項物理學是: \(samplechem.physics)")
print("例項方程式: \(samplechem.equations)")


let samplemaths = Maths(physics: "流體動力學", formulae: "千兆赫")
print("例項物理學是: \(samplemaths.physics)")
print("例項公式是: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in sa {
    // 型別轉換的條件形式
    if let show = item as? Chemistry {
        print("化學主題是: '\(show.physics)', \(show.equations)")
        // 強制形式
    } else if let example = item as? Maths {
        print("數學主題是: '\(example.physics)',  \(example.formulae)")
    }
}

// 可以儲存Any型別的陣列 exampleany
var exampleany = [Any]()

exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Any 例項")
exampleany.append(Chemistry(physics: "固體物理", equations: "兆赫"))

for item2 in exampleany {
    switch item2 {
    case let someInt as Int:
        print("整型值為 \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("Pi 值為 \(someDouble)")
    case let someString as String:
        print("\(someString)")
    case let phy as Chemistry:
        print("主題 '\(phy.physics)', \(phy.equations)")
    default:
        print("None")
    }
}

以上程式執行輸出結果為:

例項物理學是: 固體物理
例項方程式: 赫茲
例項物理學是: 流體動力學
例項公式是: 千兆赫
化學主題是: '固體物理', 赫茲
數學主題是: '流體動力學',  千兆赫
化學主題是: '熱物理學', 分貝
數學主題是: '天體物理學',  兆赫
數學主題是: '微分方程',  餘弦級數
整型值為 12
Pi 值為 3.14159
Any 例項
主題 '固體物理', 兆赫

AnyObject 例項

class Subjects {
    var physics: String
    init(physics: String) {
        self.physics = physics
    }
}

class Chemistry: Subjects {
    var equations: String
    init(physics: String, equations: String) {
        self.equations = equations
        super.init(physics: physics)
    }
}

class Maths: Subjects {
    var formulae: String
    init(physics: String, formulae: String) {
        self.formulae = formulae
        super.init(physics: physics)
    }
}

// [AnyObject] 型別的陣列
let saprint: [AnyObject] = [
    Chemistry(physics: "固體物理", equations: "赫茲"),
    Maths(physics: "流體動力學", formulae: "千兆赫"),
    Chemistry(physics: "熱物理學", equations: "分貝"),
    Maths(physics: "天體物理學", formulae: "兆赫"),
    Maths(physics: "微分方程", formulae: "餘弦級數")]


let samplechem = Chemistry(physics: "固體物理", equations: "赫茲")
print("例項物理學是: \(samplechem.physics)")
print("例項方程式: \(samplechem.equations)")


let samplemaths = Maths(physics: "流體動力學", formulae: "千兆赫")
print("例項物理學是: \(samplemaths.physics)")
print("例項公式是: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in saprint {
    // 型別轉換的條件形式
    if let show = item as? Chemistry {
        print("化學主題是: '\(show.physics)', \(show.equations)")
        // 強制形式
    } else if let example = item as? Maths {
        print("數學主題是: '\(example.physics)',  \(example.formulae)")
    }
}

var exampleany = [Any]()
exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Any 例項")
exampleany.append(Chemistry(physics: "固體物理", equations: "兆赫"))

for item2 in exampleany {
    switch item2 {
    case let someInt as Int:
        print("整型值為 \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("Pi 值為 \(someDouble)")
    case let someString as String:
        print("\(someString)")
    case let phy as Chemistry:
        print("主題 '\(phy.physics)', \(phy.equations)")
    default:
        print("None")
    }
}

以上程式執行輸出結果為:

例項物理學是: 固體物理
例項方程式: 赫茲
例項物理學是: 流體動力學
例項公式是: 千兆赫
化學主題是: '固體物理', 赫茲
數學主題是: '流體動力學',  千兆赫
化學主題是: '熱物理學', 分貝
數學主題是: '天體物理學',  兆赫
數學主題是: '微分方程',  餘弦級數
整型值為 12
Pi 值為 3.14159
Any 例項
主題 '固體物理', 兆赫

在一個switch語句的case中使用強制形式的型別轉換操作符(as, 而不是 as?)來檢查和轉換到一個明確的型別。