kotlin 关键字expect/actual的作用

在 Kotlin 多平台开发(Kotlin Multiplatform, 简称 KMP)中,expect 和 actual 是一对协同工作的修饰符关键字,它们的核心作用是:解决跨平台通用代码与平台特有 API 之间的调用与实现问题。

它们构成了 Kotlin 实现"跨平台代码共享,同时保留原生平台能力"的基础机制。

一、各自的具体分工

1、expect(期望声明)

写在通用代码模块(commonMain)中。

作用:用来定义规范和接口。它告诉 Kotlin 编译器:"我在通用代码里需要使用某种功能/类/函数,但我只在这里声明它的接口和签名,具体的实现逻辑交由各个具体平台去完成。"

特点:expect 声明的方法或类不能写具体的实现代码(没有函数体)。

2、actual(具体实现)

写在特定平台模块(如 androidMain、iosMain、jvmMain、jsMain 等)中。

作用:用来提供具体实现。它告诉 Kotlin 编译器:"这是针对特定平台,对 commonMain 中那个 expect 声明的具体实现逻辑。"

特点:必须与 expect 的名称、包路径、参数类型和返回值完全匹配。

二、代码示例

  1. 声明平台特有函数(以获取设备名称为例)
    通用模块 (commonMain):

    // 声明一个期待在平台层实现的函数
    expect fun getDeviceName(): String

    // 通用代码可以直接调用这个 expect 函数
    fun printDeviceInfo() {
    println("Current device: ${getDeviceName()}")
    }

Android 模块 (androidMain):

复制代码
// 提供 Android 端的具体实现
actual fun getDeviceName(): String {
    return "Android " + android.os.Build.MODEL
}

iOS 模块 (iosMain):

复制代码
import platform.UIKit.UIDevice

// 提供 iOS 端的具体实现
actual fun getDeviceName(): String {
    return UIDevice.currentDevice.systemName + " " + UIDevice.currentDevice.systemVersion
}
  1. 利用类型别名(Typealias)直接绑定原生类
    actual 不仅可以写函数体,还可以通过 typealias 直接复用平台已有的原生类,无需重复封装:

通用模块 (commonMain):

复制代码
expect class AtomicInt(initialValue: Int) {
    fun get(): Int
    fun incrementAndGet(): Int
}

JVM / Android 模块 (jvmMain):

复制代码
// 直接将 JVM 原生的 AtomicInteger 绑定位 actual 实现
import java.util.concurrent.atomic.AtomicInteger

actual typealias AtomicInt = AtomicInteger

三、核心特点与优势

1、零运行时开销(Zero Overhead)

与传统的依赖注入(DI)或运行时条件判断(if (isAndroid))不同,expect/actual 是在编译期(Compile Time)完成链接与替换的。编译后的平台产物中完全没有多余的抽象层或反射,性能与原生代码一致。

2、类型安全

编译器会强制检查。如果某个平台(如 iosMain)忘记写对应的 actual 实现,或者参数/返回值类型与 expect 不匹配,项目在编译阶段就会直接报错,保证不会把缺失实现的代码带到运行时。

3、不仅限于函数

expect/actual 机制可以修饰:

函数(fun)

类与接口(class / interface)

属性(val / var)

枚举(enum class)

类型别名(typealias)

四、最佳实践建议

尽管 expect/actual 很强大,但在实际 KMP 项目开发中,建议不要过度使用它:

优先抽象接口(Interface):对于复杂的业务模块(如网络库、数据库、蓝牙等),建议在 commonMain 中定义标准 Kotlin interface,然后在各平台实现,通过依赖注入(如 Koin)或构造函数传递。

何时使用 expect/actual:适合用于底层基础 API(如获取系统时间、UUID 生成、平台日志打印、文件路径获取等)或绑定平台已有工具类。

相关推荐
mmsx4 小时前
Android 上的 AI 对话链路:流式响应、SSE 解析与三级降级
android·kotlin
YB13754 小时前
Kotlin 引用操作符::
kotlin
维克兜率天1 天前
【维克】弹性策略:用“乖离率“捕捉超跌反弹
android·开发语言·python·深度学习·kotlin·量化
传奇开心果编程1 天前
【用案例学Material 3 Expressive】第1课:从一封邮件开始,感受安卓设计新语言的表现力
android·学习·ui·kotlin·android jetpack
mmsx1 天前
Android 状态保持:进程被杀、旋屏与后台任务的存活术
android·kotlin
传奇开心果编程2 天前
【Jetpack Compose进阶学与练】第14课:系列收尾复习总结;Compose项目常见坑点汇总;学习路线与后续学习方向
android·学习·ui·kotlin·android jetpack
花开路口2 天前
线程安全完全指南:从 Java 到 Kotlin,一文吃透并发编程
java·kotlin
hai_android2 天前
子 View 被压小时,如何向父容器"告状"?——MEASURED_STATE_TOO_SMALL 向上传递机制
android·kotlin·android jetpack
怪奇云呼军2 天前
从 ElevenLabs 看工具调用:闪电智能 Voice Agent 的企业集成验收设计
android·大数据·运维·服务器·网络·人工智能·kotlin
mmsx2 天前
Android UI 复用体系:泛型基类、骨架与插槽
android·kotlin