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 生成、平台日志打印、文件路径获取等)或绑定平台已有工具类。

相关推荐
汪海游龙8 小时前
流式回复结尾的那一下闪:逐帧定位 Compose 聊天列表的三处布局跳动
android·性能优化·kotlin
传奇开心果编程10 小时前
【Compose Multiplatform跨端声明式UI实用技术】第20课:CMP跨平台经典示例深度解析
kotlin·移动开发·跨平台·编程语言理论·开发范式·编程框架·声明式ui
敲代码的瓦龙11 小时前
Jetpack?lifecycle!!!
android·kotlin
Kapaseker16 小时前
为什么程序员始终无法彻底解决内存泄漏?
android·kotlin
汤姆宝库16 小时前
推理工程深拆:调度、量化与投机解码
android·开发语言·kotlin
传奇开心果2 天前
【Compose Multiplatform跨端声明式UI实用技术】第9课:跨平台 ViewModel 与状态架构
android·kotlin
andyweike2 天前
kotlin dsl library工程怎么配置
android·开发语言·kotlin
high一马平川3 天前
# SystemUI Dagger2 精读 · 第 2 章 @Inject:1200 处构造注入,和 1 处例外
android·java·kotlin
小铁-Android3 天前
CompletableDeferred:Kotlin 协程中用于一次性挂起通信的工具
android·kotlin