Kotlin類型的檢查與轉換

is!is 操作符

我們可以在運行時通過使用 is 操作符或其否定形式 !is 來檢查對象是否符合給定類型:

if (obj is String) {
    print(obj.length)
}

if (obj !is String) { // 與 !(obj is String) 相同
    print("Not a String")
}
else {
    print(obj.length)
}

智能轉換

在許多情況下,不需要在 Kotlin 中使用顯式轉換操作符,因爲編譯器跟蹤
不可變值的 is-檢查,並在需要時自動插入(安全的)轉換:

fun demo(x: Any) {
    if (x is String) {
        print(x.length) // x 自動轉換爲字符串
    }
}

編譯器足夠聰明,能夠知道如果反向檢查導致返回那麼該轉換是安全的:

    if (x !is String) return
    print(x.length) // x 自動轉換爲字符串

或者在 &&|| 的右側:

    // `||` 右側的 x 自動轉換爲字符串
    if (x !is String || x.length == 0) return

    // `&&` 右側的 x 自動轉換爲字符串
    if (x is String && x.length > 0) {
        print(x.length) // x 自動轉換爲字符串
    }

這些 智能轉換 用於 when{: .keyword }-表達式
while{: .keyword }-循環 也一樣:

when (x) {
    is Int -> print(x + 1)
    is String -> print(x.length + 1)
    is IntArray -> print(x.sum())
}

請注意,當編譯器不能保證變量在檢查和使用之間不可改變時,智能轉換不能用。
更具體地,智能轉換能否適用根據以下規則:

  • val{: .keyword } 局部變量——總是可以;
  • val{: .keyword } 屬性——如果屬性是 private 或 internal,或者該檢查在聲明屬性的同一模塊中執行。智能轉換不適用於 open 的屬性或者具有自定義 getter 的屬性;
  • var{: .keyword } 局部變量——如果變量在檢查和使用之間沒有修改、並且沒有在會修改它的 lambda 中捕獲;
  • var{: .keyword } 屬性——決不可能(因爲該變量可以隨時被其他代碼修改)。

「不安全的」轉換操作符

通常,如果轉換是不可能的,轉換操作符會拋出一個異常。因此,我們稱之爲不安全的
Kotlin 中的不安全轉換由中綴操作符 as{: .keyword }(參見operator precedence)完成:

val x: String = y as String

請注意,null{: .keyword } 不能轉換爲 String 因該類型不是可空的,
即如果 y 爲空,上面的代碼會拋出一個異常。
爲了匹配 Java 轉換語義,我們必須在轉換右邊有可空類型,就像:

val x: String? = y as String?

「安全的」(可空)轉換操作符

爲了避免拋出異常,可以使用安全轉換操作符 as?{: .keyword },它可以在失敗時返回 null{: .keyword }:

val x: String? = y as? String

請注意,儘管事實上 as?{: .keyword } 的右邊是一個非空類型的 String,但是其轉換的結果是可空的。