expect/actual-mekanismen til platform-API'er
Deklarér forventede deklarationer i fælles kode, og angiv faktiske implementeringer pr. platform.
expect/actual-mekanismen til platform-API'er er en gratis Kotlin Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Kotlin Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Kotlin Academy-kurset indeholder 4 lektioner i alt.
expect/actual-mønstret
expect erklærer en API-kontrakt i commonMain. Hver platform leverer en actual-implementering. Kompileren håndhæver, at alle målplatforme har en actual.
// commonMain:
expect fun platformName(): String
// androidMain:
actual fun platformName(): String = "Android ${android.os.Build.VERSION.SDK_INT}"
// iosMain:
actual fun platformName(): String = UIDevice.currentDevice.systemName()expect class
expect class erklærer en klasse med dens API i commonMain. Hver platform leverer den fulde implementering.
// commonMain:
expect class DateTime {
fun format(pattern: String): String
val timestamp: Long
}
// androidMain:
actual class DateTime {
actual val timestamp = System.currentTimeMillis()
actual fun format(pattern: String): String =
java.text.SimpleDateFormat(pattern).format(java.util.Date(timestamp))
}expect object
expect object erklærer en singleton med sin kontrakt. Det er nyttigt til platformspecifikke hjælpefunktioner som logning, indstillinger eller analyse.
// commonMain:
expect object Logger {
fun debug(msg: String)
fun error(msg: String, cause: Throwable? = null)
}
// androidMain:
actual object Logger {
actual fun debug(msg: String) = android.util.Log.d("App", msg)
actual fun error(msg: String, cause: Throwable?) =
android.util.Log.e("App", msg, cause)
}expect val / fun på øverste niveau
expect val og expect fun på øverste niveau er enkle og fungerer godt til tilstandsløse platformspecifikke hjælpefunktioner.
// commonMain:
expect val isDebugBuild: Boolean
expect fun generateUUID(): String
// androidMain:
actual val isDebugBuild: Boolean = BuildConfig.DEBUG
actual fun generateUUID(): String = java.util.UUID.randomUUID().toString()
// iosMain:
actual val isDebugBuild: Boolean = false // or a native flag
actual fun generateUUID(): String = NSUUID().UUIDString()expect fun med standardimplementering
Fra og med Kotlin 1.9 kan expect fun have en standardimplementering via expect fun f() { }. Platformene kan tilsidesætte den eller bruge standarden.
// commonMain (Kotlin 1.9+):
expect fun log(msg: String) {
println("[DEFAULT] $msg") // used if no actual overrides
}
// androidMain:
actual fun log(msg: String) = android.util.Log.d("KMP", msg)
// iosMain (uses default):
// no actual needed — default is usedactual typealias
Hvis en platform allerede har præcis den klasse, du har brug for, skal du bruge actual typealias til at pege på den i stedet for at indpakke den.
// commonMain:
expect class AtomicInt {
fun get(): Int
fun incrementAndGet(): Int
}
// androidMain / jvmMain:
actual typealias AtomicInt = java.util.concurrent.atomic.AtomicInteger
// iosMain:
actual class AtomicInt {
private var value = 0
actual fun get() = value
actual fun incrementAndGet() = ++value
}expect interface (indirekte mønster)
For større fleksibilitet skal du erklære en grænseflade i commonMain og kun bruge expect/actual til den fabrik, der opretter platforminstansen.
// commonMain:
interface FileStorage {
suspend fun readFile(path: String): ByteArray
suspend fun writeFile(path: String, data: ByteArray)
}
expect fun createFileStorage(): FileStorage
// androidMain:
actual fun createFileStorage(): FileStorage = AndroidFileStorage()
// iosMain:
actual fun createFileStorage(): FileStorage = IosFileStorage()Test med expect/actual
I commonTest skal du teste den fælles API. De faktiske implementeringer køres under platformspecifikke testopgaver (testDebugUnitTest på Android, iosX64Test på iOS).
// commonTest:
import kotlin.test.Test
import kotlin.test.assertNotNull
class PlatformTest {
@Test
fun testUUID() {
val uuid = generateUUID()
assertNotNull(uuid)
println("UUID: $uuid")
}
}Almindelige faldgruber
Enhver erklæret expect skal have en actual i ALLE konfigurerede målplatforme, ellers mislykkes projektbygningen. Manglende actual-implementeringer opdages ved kompilering.
// If you add a new target (e.g., jvmMain), you must add:
// actual fun platformName(): String = "JVM"
// Otherwise:
// error: Expected function platformName has no actual declaration in module :shared for JVM
fun main() { println("Missing actuals = compile error") }expect annotation class
expect annotation class muliggør platformspecifik tilknytning af annotationer — f.eks. tilknytning af en fælles annotation, der minder om @Parcelize, til Androids Parcelize-plugin.
// commonMain:
expect annotation class CommonParcelize()
// androidMain:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
actual annotation class CommonParcelize
// iosMain:
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
actual annotation class CommonParcelizeEksempel fra virkeligheden: Keychain/Preferences
Et typisk eksempel fra virkeligheden på expect/actual er en grænseflade til sikker lagring, hvor Android bruger EncryptedSharedPreferences, og iOS bruger Keychain.
// commonMain:
expect class SecureStorage {
fun save(key: String, value: String)
fun get(key: String): String?
}
// androidMain:
actual class SecureStorage {
private val prefs = /* EncryptedSharedPreferences */ mapOf<String,String>()
actual fun save(key: String, value: String) { /* ... */ }
actual fun get(key: String): String? = null // simplified
}Hurtigt tjek
Hvad sker der ved kompilering, hvis en expect-erklæring ikke har en actual til en målplatform?
Opsummering
expect erklærer API'et i commonMain. actual leverer platformimplementeringen. Brug actual typealias, når platformen allerede har den nødvendige type. Manglende actual-implementeringer opdages ved kompilering — ingen overraskelser ved kørsel.
Lær Kotlin med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 51
- Lektioner
- 203
Ofte stillede spørgsmål
Er lektionen “expect/actual-mekanismen til platform-API'er” gratis?
Ja — alle 3 lektioner i læringssporet Kotlin Academy, inklusive “expect/actual-mekanismen til platform-API'er”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Kotlin Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “expect/actual-mekanismen til platform-API'er”?
Deklarér forventede deklarationer i fælles kode, og angiv faktiske implementeringer pr. platform. Du øver dig i Kotlin Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Kotlin Academy?
Der kræves ingen tidligere erfaring. Kotlin Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “expect/actual-mekanismen til platform-API'er”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Kotlin Academy-lektion?
Ja. Alle Kotlin Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- KMP-projektstruktur: commonMain, androidMain, iosMain
- expect/actual-mekanismen til platform-API'er
- Deling af Repository- og Use Case-lag
- Dependency injection i KMP med Koin