ZetCode

Kotlin as? 关键字

最后修改于 2025 年 4 月 19 日

Kotlin 的安全转换操作符 as? 提供了一种空安全的方式来执行类型转换。与不安全的 as 操作符不同,as? 在转换失败时返回 null,而不是抛出异常。本教程将通过实际例子深入探讨 as? 关键字。

基本定义

Kotlin 中的 as? 关键字是安全转换操作符。它尝试将一个值转换为指定的类型,如果转换不可行,则返回 null。这在处理未知或动态类型时特别有用。

安全转换与 Kotlin 的空安全系统完美契合。它通过在转换失败时返回 null 来防止 ClassCastException。使用 as? 时,结果类型始终是可空的。

基本安全转换示例

此示例演示了 as? 的基本用法,用于在类型之间进行安全转换。当类型不兼容时,转换会返回 null。

BasicSafeCast.kt
package com.zetcode

fun main() {

    val obj: Any = "Hello Kotlin"
    val str: String? = obj as? String
    val num: Int? = obj as? Int
    
    println(str) // Output: Hello Kotlin
    println(num) // Output: null
}

在这里,我们首先成功地转换为 String,因为 obj 包含一个字符串。第二次转换为 Int 失败并返回 null。两个结果都是可空类型。

使用 When 表达式进行安全转换

as? 操作符与 Kotlin 的 when 表达式配合使用,可以很好地处理类型。这种模式对于安全地处理不同类型很有用。

WhenSafeCast.kt
package com.zetcode

fun processValue(value: Any) {
    when (val str = value as? String) {
        null -> println("Not a string")
        else -> println("String length: ${str.length}")
    }
}

fun main() {

    processValue("Kotlin") // Output: String length: 6
    processValue(42)       // Output: Not a string
}

when 表达式检查安全转换为 String 是否成功。null 分支处理失败的转换,而 else 分支处理成功转换的字符串。这比手动空检查更简洁。

类层次结构中的安全转换

as? 可以在类层次结构中安全地转换对象。这在处理多态集合或返回基类型的 API 时很有用。

HierarchySafeCast.kt
package com.zetcode

open class Animal
class Dog : Animal() {
    fun bark() = "Woof!"
}
class Cat : Animal() {
    fun meow() = "Meow!"
}

fun main() {

    val animals: List<Animal> = listOf(Dog(), Cat(), Dog())
    
    animals.forEach { animal ->
        (animal as? Dog)?.let {
            println(it.bark())
        }
    }
    // Output: Woof! Woof!
}

我们使用 as? 安全地将每个 Animal 转换为 Dog,然后使用 ?.let 仅处理 Dog。由于转换为 Dog 的过程返回 null,因此 Cat 被忽略。这可以安全地处理混合集合。

集合的安全转换

在使用混合类型的集合时,as? 有助于安全地过滤和处理特定类型的元素,而不会冒异常的风险。

CollectionSafeCast.kt
package com.zetcode

fun main() {

    val mixedList: List<Any> = listOf(1, "Two", 3.0, "Four", 5)
    
    val strings = mixedList.mapNotNull { it as? String }
    println(strings) // Output: [Two, Four]
    
    val numbers = mixedList.mapNotNull { it as? Int }
    println(numbers) // Output: [1, 5]
}

使用 mapNotNullas?,我们可以安全地提取特定类型的元素。失败的转换变为 null,并被 mapNotNull 过滤掉。这创建了仅包含成功转换的元素的新集合。

泛型函数中的安全转换

泛型函数可以利用 as? 安全地尝试转换为类型参数。这对于创建灵活的类型安全实用程序很有用。

GenericSafeCast.kt
package com.zetcode

fun <T> safeCastOrDefault(value: Any, defaultValue: T): T {
    return value as? T ?: defaultValue
}

fun main() {

    val str: String = safeCastOrDefault(123, "Default")
    println(str) // Output: Default
    
    val num: Int = safeCastOrDefault("456", 0)
    println(num) // Output: 0
    
    val success: String = safeCastOrDefault("Hello", "Default")
    println(success) // Output: Hello
}

这个泛型函数尝试使用 as? 将输入转换为类型 T。如果转换失败,它将返回提供的默认值。该函数适用于任何类型,同时保持类型安全。

密封类中的安全转换

密封类与 as? 配合使用,非常适合进行详尽的类型检查。这种模式在 Kotlin 中很常见,用于表示受限的类层次结构。

SealedSafeCast.kt
package com.zetcode

sealed class Result
class Success(val data: String) : Result()
class Error(val message: String) : Result()

fun handleResult(result: Result) {
    when {
        (result as? Success) != null -> println("Success: ${result.data}")
        (result as? Error) != null -> println("Error: ${result.message}")
    }
}

fun main() {

    handleResult(Success("Data loaded")) // Output: Success: Data loaded
    handleResult(Error("Network error")) // Output: Error: Network error
}

我们使用 as? 安全地检查每个密封类的子类型。when 表达式处理所有可能的情况,而不需要 else 分支。这种方法对于密封的层次结构既安全又详尽。

接口的安全转换

as? 可以安全地检查接口的实现。这在处理可能选择性地实现某些接口的对象时很有用。

InterfaceSafeCast.kt
package com.zetcode

interface Loggable {
    fun log(): String
}

class User(val name: String) : Loggable {
    override fun log() = "User: $name"
}

class Product(val id: Int)

fun logIfPossible(obj: Any) {
    (obj as? Loggable)?.let {
        println(it.log())
    }
}

fun main() {

    logIfPossible(User("Alice")) // Output: User: Alice
    logIfPossible(Product(123))  // No output
}

该函数使用 as? 安全地检查一个对象是否实现了 Loggable 接口。只有 Loggable 对象才会被处理,其他对象会被安全地忽略。这种模式比显式的接口检查更简洁。

安全转换的最佳实践

来源

Kotlin 类型转换文档

本教程深入介绍了 Kotlin 的 as? 关键字,展示了它在各种场景中的用法。安全转换有助于编写能够优雅地处理类型不匹配的健壮代码。与 Kotlin 的空安全相结合,它可以防止许多常见的运行时错误。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有多年的编程经验。自 2007 年以来,我一直在撰写编程文章。到目前为止,我撰写了 1400 多篇文章和 8 本电子书。我拥有超过八年的编程教学经验。

列出 所有 Kotlin 教程