1. Actual / expect
2026/1/31大约 3 分钟
1. Actual / expect
你看到的 actual 关键字,是 Kotlin 多平台(Kotlin Multiplatform, KMP) 中的核心机制之一。它和 expect 成对出现,用于在不同平台(JVM、JS、Native 等)上提供不同的实现,同时共享同一套接口。
🔍 一句话解释 actual
actual 表示“这是某个 expect 声明在当前平台上的具体实现”。
🧱 基本原理:expect / actual 对
1. 在 commonMain(共享代码)中声明 expect
// commonMain
expect class EmbeddedServer<T, C>()
expect fun createServer(): EmbeddedServer<*, *>这里只声明“有这个类/函数”,但不提供实现。
2. 在 jvmMain、jsMain 等平台模块中提供 actual 实现
// jvmMain
actual class EmbeddedServer<T, C> {
actual fun start(wait: Boolean) { /* JVM-specific code */ }
}
actual fun createServer(): EmbeddedServer<*, *> = EmbeddedServer()✅ 这就是你看到的代码所在的位置 —— 这是 Ktor 在 JVM 平台的具体实现。
❓ 为什么类、构造器、属性上都能加 actual?
因为 expect 可以声明任何东西,所以 actual 也必须能对应实现它们:
| 声明位置 | expect 示例 | actual 示例 |
|---|---|---|
| 类 | expect class Foo | actual class Foo |
| 构造器 | expect class Foo() { ... } | actual constructor(...) |
| 属性 | expect val x: Int | actual val x: Int = 42 |
| 函数 | expect fun hello() | actual fun hello() { ... } |
💡 注意:如果 expect 类有主构造器,actual 类也必须用 actual constructor(...) 显式声明。
📌 你代码中的 actual 详解
public actual class EmbeddedServer<...> // ← 这个类是 common 中 expect class 的 JVM 实现
actual constructor( // ← 主构造器也是 actual(因为 expect 类有构造器)
private val rootConfig: ServerConfig,
...
) {
public actual val monitor: Events = ... // ← 属性实现
public actual val environment: ApplicationEnvironment = ...
public actual val application: Application // ← 带自定义 getter 的属性
get() = currentApplication()
public actual fun start(wait: Boolean): EmbeddedServer<...> { ... } // ← 函数实现
}✅ 为什么需要这样设计?(以 Ktor 为例)
Ktor 是一个多平台框架:
- 在 JVM 上,用 Netty/Jetty/Tomcat 启动服务器
- 在 Android (Native) 上,可能用 OkHttp 或其他方式
- 在 JS (Node.js) 上,用 Node 的 HTTP 模块
但用户希望写同一套 API:
embeddedServer(Netty, port = 8080) {
routing { get("/") { ... } }
}.start()→ 所以 Ktor 在 common 中定义 expect class EmbeddedServer,
→ 然后在 JVM/JS/Native 分别用 actual 提供平台专属实现。
🚫 常见误区
| 误区 | 正确理解 |
|---|---|
“actual 是修饰符,像 public” | ❌ 它是多平台实现标记,只在有 expect 时才有意义 |
“没有 expect 也能用 actual” | ❌ 编译会报错:“No corresponding expected declaration” |
“actual 可以随便加” | ❌ 必须和 expect 的签名完全匹配(类型、泛型、参数名等) |
🔧 如何查看对应的 expect 声明?
在 IntelliJ IDEA 中:
- 把光标放在 actual class EmbeddedServer
- 按 Ctrl + B(Go to Declaration)
- IDE 会跳转到 commonMain 中的 expect class EmbeddedServer
| 关键点 | 说明 |
|---|---|
actual 是什么? | Kotlin 多平台中,平台特定实现的标记 |
| 为什么到处都有? | 因为 expect 声明了类、构造器、属性、函数,所以 actual 必须一一对应实现 |
| 能不能不用? | 如果你只写 JVM 代码,可以不用;但框架(如 Ktor)必须用来支持多平台 |
| 和普通 Kotlin 代码区别? | 没有 expect/actual 的项目,根本不会出现 actual 关键字 |
所以你之前没见过 actual,很可能是因为你一直在写纯 JVM 单平台项目。一旦接触 Ktor、Compose Multiplatform、KMM 等多平台库,就会频繁见到它。
这就是 Kotlin 实现“一次编写,多端运行”的关键机制之一 🎯