Ce face expect și actual
În proiectele Kotlin Multiplatform, cea mai mare parte a codului stă într-un modul comun (commonMain), care se compilează pentru mai multe platforme: JVM/Android, iOS, web, desktop. Unele lucruri diferă însă de la o platformă la alta: ora sistemului, generatorul de UUID, stocarea fișierelor. Pentru ele scrii în codul comun o declarație expect (fără implementare), iar în fiecare modul de platformă (jvmMain, iosMain, jsMain) o implementare actual cu exact aceeași semnătură.
Pot fi expect: funcții, proprietăți, clase, obiecte, interfețe, enum-uri și adnotări. Compilatorul verifică faptul că fiecare platformă are un actual potrivit. Recomandarea oficială este să folosești funcții și interfețe expect (sau o interfață obișnuită cu implementări injectate) și să eviți clasele expect, care sunt încă Beta.
Mecanismul are nevoie de un proiect Gradle multiplatform; un singur fișier compilat cu kotlinc pentru JVM nu poate avea expect fără actual. De aceea exemplele de mai jos arată structura proiectului și rezultatul de pe fiecare platformă, fără să fie rulate aici.
Exemple
Exemplul 1: O funcție cu implementare pe fiecare platformă
Codul comun folosește platforma() fără să știe unde rulează. Rezultatul depinde de ținta pe care o rulezi.
// src/commonMain/kotlin/Salut.kt
expect fun platforma(): String
fun salut() = "Salut de pe ${platforma()}!"
// src/jvmMain/kotlin/Platforma.jvm.kt
actual fun platforma(): String = "JVM " + System.getProperty("java.version")
// src/iosMain/kotlin/Platforma.ios.kt
import platform.UIKit.UIDevice
actual fun platforma(): String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
Rezultat (pe JVM, respectiv pe un iPhone)
Salut de pe JVM 27!
Salut de pe iOS 26.0!
Exemplul 2: Alternativa recomandată: interfață comună
În loc de expect class, codul comun definește o interfață, iar fiecare platformă dă o implementare. Partea comună de mai jos rulează pe JVM ca un program obișnuit.
interface Ceas {
fun oraCurenta(): String
}
class CeasFix(private val ora: String) : Ceas {
override fun oraCurenta() = ora
}
class Programare(private val ceas: Ceas) {
fun mesaj(pacient: String) = "Pacientul $pacient a fost înregistrat la ${ceas.oraCurenta()}"
}
fun main() {
val p = Programare(CeasFix("09:30"))
println(p.mesaj("Ana Pop"))
}
Rezultat
Pacientul Ana Pop a fost înregistrat la 09:30
Greșeli frecvente
- Un
expectfărăactualpe una dintre platforme: compilarea pentru acea platformă se oprește cu o eroare care spune că declarațiaexpectnu areactualîn modulul respectiv. - Semnături diferite între
expectșiactual(alt tip de parametru, alt tip returnat): compilatorul le tratează ca declarații diferite și dă eroare. - Folosirea lui
expectpentru orice diferență mică: de multe ori o interfață și injectarea implementării sunt mai simple și mai ușor de testat.
Comenzi înrudite
external: external declară o funcție implementată în afara lui Kotlin: în cod nativ prin JNI pe JVM, sau în JavaScript pentru Kotlin/JS.interface: interface descrie ce poate face un obiect (metode și proprietăți), fără stare; o clasă poate implementa mai multe interfețe.kotlinc: Compilatorul Kotlin din linia de comandă: transformă fișierele .kt într-un program care rulează pe JVM.annotation class și ținte de adnotare: annotation class declară o adnotare (@Nume) care adaugă informații la cod; @field:, @get:, @file: aleg exact unde se pune.