1. Kotlin 中的 actual 关键字简介

在本教程中,我们将深入讲解 Kotlin 中的 actual 关键字,以及它与 expect 配合使用的典型场景。

2. Kotlin Multiplatform 开发基础

要理解 actual,首先需要了解 Kotlin Multiplatform Module (KMM) 的基本概念。

KMM 是 Kotlin 提供的一项功能,允许我们用 Kotlin 编写可跨平台运行的代码。这对于移动端开发尤其有用 —— 你可以将 Android 和 iOS 共用的业务逻辑统一管理,减少重复开发。

当然,不同平台总有其特有的 API,比如网络请求、系统时间、UI 渲染等。这些部分仍需在各自平台实现,比如 Android 上使用 Kotlin/Java,iOS 上使用 Swift/Objective-C。

3. 共享模块(Shared Module)的结构

共享模块是 KMM 的核心,它会被 Android 和 iOS 工程分别引用。这个模块本身是纯 Kotlin 编写的,但通过 Kotlin Native 项目 编译成目标平台的原生代码(如 iOS 的 .framework 或 Android 的 .jar)。

尽管共享模块的目标是复用代码,但有些功能仍然需要调用平台 API,比如获取系统时间戳:

举个例子:
你想在共享模块中获取当前时间戳,但不同平台的系统时间 API 不一样。这时就需要使用 expectactual 来桥接差异。

4. expect 与 actual 的作用

4.1 expect:声明一个需要平台实现的接口

在共享模块中,我们使用 expect 声明一个类或函数的结构,但不提供具体实现:

expect class DateTimeApi() {
    fun getCurrentTimestamp(): Long
}

这段代码只是告诉编译器:“这里有一个类,它有一个方法,但具体怎么实现,得看平台”。

4.2 actual:提供平台特定的实现

在 Android 或 iOS 的模块中,我们使用 actual 来提供具体实现。例如,在 Android 上可能是这样:

actual class DateTimeApi actual constructor() {
    actual fun getCurrentTimestamp(): Long {
        return OffsetDateTime.now().toEpochSecond()
    }
}

而在 iOS 上则可能是这样:

actual class DateTimeApi actual constructor() {
    actual fun getCurrentTimestamp(): Long {
        return NSDate.date().timeIntervalSince1970().toLong()
    }
}

⚠️ 注意: actual 必须和 expect 的签名完全匹配,包括类名、方法名、参数类型等。否则编译器会报错。

4.3 编译器如何工作?

Kotlin 编译器会在构建最终的二进制文件时,确保每个 expect 声明都有对应的 actual 实现。如果找不到匹配的实现,编译失败。✅

这确保了共享模块的健壮性和跨平台兼容性。

5. 总结

  • expect 用于在共享模块中声明一个类、函数或属性,但不提供实现。
  • actual 用于在特定平台模块中提供 expect 声明的实际实现。
  • 二者必须成对出现,且签名一致。
  • 使用这套机制可以优雅地实现 Kotlin Multiplatform 下的平台适配逻辑。

📌 示例代码地址:
完整代码可在 GitHub 仓库 找到。

小贴士:
使用 expect/actual 是 Kotlin Multiplatform 的核心技巧之一,尤其适合处理跨平台差异(如网络、文件、系统时间等)。合理使用可以大幅减少重复代码,提高开发效率。


原始标题:Kotlin actual Keyword