expect/actual — mahiyyəti, KMM açar sözləri və necə işlədikləri

Müəllif: IT Sectr Dərc olunub: 2026-06-05 Oxuma vaxtı: 8 dəq

expect/actual — Kotlin Multiplatform mexanizmidir, platformadan asılı API-ləri ümumi kodda bəyan etməyə imkan verir. expect açar sözü commonMain-də funksiya, sinif və ya xassənin kontraktını yaradır, actual açar sözü isə hər platforma üçün konkret implementasiya təqdim edir. Kompilyator hər expect bəyannaməsinə bütün hədəf platformalarda actual implementasiyanın uyğun olduğunu yoxlayır. JetBrains, 2025 məlumatlarına görə, bu mexanizm KMM layihələrinin 80%-də platforma biznes məntiqini həyata keçirmək üçün istifadə olunur.

Əsas məqamlar

  • expect — ümumi kodda funksiya, sinif və ya xassənin kontraktını bəyan etmək üçün açar söz.
  • actual — expect bəyannaməsinin platforma implementasiyasını təmin etmək üçün açar söz.
  • commonMain — expect bəyannamələrinin yerləşdiyi ümumi kod source set-i.
  • Kompilyator yoxlaması — kompilyator bütün hədəf platformalar üçün actual implementasiyaların mövcudluğuna zəmanət verir.
  • Source set — platforma actual implementasiyalarının yerləşdiyi dəstlər (iosMain, androidMain).

expect/actual nədir?

expect/actual — platforma yönümlü proqramlaşdırmanı həyata keçirmək üçün Kotlin Multiplatform-un deklarativ mexanizmidir. O, API-ni bir dəfə ümumi modulda (expect) təsvir etməyə və onu hər platforma üçün ayrıca (actual) həyata keçirməyə imkan verir. İnterfeyslərdən fərqli olaraq, expect/actual virtual çağırışlar yaratmır — kompilyator expect və actual bəyannamələrini kompilyasiya mərhələsində birləşdirir və bu da dinamik dispetçerizasiya üçən əlavə yükü aradan qaldırır.

expect/actual tarixi 2017-ci ildə Kotlin Multiplatform’un yaranması ilə başladı. Əvvəlcə mexanizm expect/actual declarations adlanırdı və eksperimental idi. Kotlin 1.2-də expect annotasiyaları əlavə edildi, Kotlin 1.3-də isə expect/actual siniflər və funksiyalar üçün stabilləşdi. Tədricən mexanizm genişləndi: Kotlin 1.6-də companion obyektləri üçün expect/actual dəstəyi, Kotlin 1.7-də — enum sinifləri üçün, Kotlin 2.0-da isə — typealias üçün əlavə edildi.

expect/actual’ın əsas xüsusiyyəti — kompilyasiya səviyyəsində təhlükəsizlik. Proqramçı commonMain-də expect bəyannaməsi əlavə etdikdə, lakin iOS üçün actual implementasiyanı unutduqda, kompilyator xəta verir. Bu, refleksiya və ya platforma kodunun dinamik yüklənməsi yanaşmaları üçün xarakterik olan runtime xətalarının qarşısını alır.

expect/actual mexanizmi necə işləyir

Mexanizm expect/actual source set — Kotlin Multiplatform modul sistemi səviyyəsində işləyir. Bütün platformalar üçün əlçatan ümumi kod commonMain source set-ində yerləşir. Platformadan asılı kod — iosMain, androidMain, macosMain və s. commonMain-də expect açar sözü API-ni bəyan edir, platforma source set-ində actual açar sözü isə implementasiyanı təmin edir. Kompilyator onları kod generasiyası mərhələsində birləşdirir və expect funksiyasının çağırışını hədəf platforma üçün müvafiq actual implementasiya ilə əvəz edir.

Tipik KMM layihəsində source set iyerarxiyası belədir: commonMain expect bəyannamələrini ehtiva edir, iosMainandroidMain actual implementasiyaları ehtiva edir. iOS üçün kompilyasiya zamanı iosMain-dən, Android üçün kompilyasiya zamanı isə androidMain-dən actual istifadə olunur. Source set’lər aralıq ola bilər (məsələn, müəyyən arxitektura üçün iosArm64Main), bu da müxtəlif cihazlar üçün implementasiyaları dəqiqləşdirməyə imkan verir.

kotlin
// commonMain — expect bəyannaməsi
expect fun getPlatformName(): String

// androidMain — Android üçün actual
actual fun getPlatformName(): String = "Android"

// iosMain — iOS üçün actual
actual fun getPlatformName(): String = "iOS"

Kompilyatorun actual implementasiyaları yoxlaması

Kotlin kompilyatoru expect/actual ilə işlərkən bir neçə şərti yoxlayır. Hər expect bəyannaməsi hər aktiv platforma üçün actual implementasiyaya malik olmalıdır. actual bəyannaməsinin imzası expect imzası ilə uyğun olmalıdır (@OptionalExpectation annotasiyası bu tələbi yumşala bilər). Giriş modifikatorları, qaytarma tipi və parametrlər eyni olmalıdır. Kompilyator həmçinin expect və actual bəyannamələri arasında tsiklik asılılıqların olmamasını yoxlayır.

expect/actual növləri: funksiyalar, siniflər, xassələr

expect/actual bir neçə bəyannamə növünü dəstəkləyir. Platforma əməliyyatları üçün expect/actual funksiyaları, nativ implementasiya tələb edən obyektlər üçün expect/actual sinifləri və sabitlər və parametrlər üçün expect/actual xassələri ən çox istifadə olunur. Hər növün öz istifadə qaydaları və məhdudiyyətləri var.

expect/actual funksiyaları — ən sadə və geniş yayılmış növdür. Onlar vaxtı əldə etmək, faylları oxumaq və ya HTTP sorğuları göndɘrmɘk kimi platforma API-lɘrini çağırmaq üçün istifadə olunur. expect/actual sinifləri nativ kodla birbaşa qarşılıqlı əlaqədə olan obyektlɘr yaratmaq üçün tətbiq edilir (məsələn, kameraya, geolokasiyaya və ya açar saxlayıcıya giriş üçün). expect/actual xassələri (val) platforma sabitləri — OS adı, SDK versiyası və ya sistem kataloquna yol üçün uyğundur.

Bəyannamə növüAçar sözlərİstifadə nümunəsi
Funksiyaexpect fun / actual funCihazın unikal identifikatorunu əldə etmək
Sinifexpect class / actual classSecureStorage-a giriş (Keychain / EncryptedSharedPreferences)
Xassəexpect val / actual valCari platforma (iOS / Android)
Enum sinifexpect enum / actual enumMövcud tətbiq icazələrinin siyahısı
Typealiasexpect typealias / actual typealiasPlatforma üçün spesifik řəbəkə cavab tipi

expect/actual məhdudiyyətləri

Kotlin-in bütün konstruksiyaları expect/actual ilə istifadə oluna bilməz. expect bəyannaməsi bədən ehtiva edə bilməz — yalnız imza. expect sinifi parametrləri olan konstruktora malik ola bilməz (boş əsas konstruktor olmalıdır). Enum expect/actual üçün bütün sabitlər expect və actual-da eyni olmalıdır. expect xassələri val (var deyil) olmalıdır, çünki platforma xassələri üçün ümumi modulda vəziyyətin saxlanmasının mənası yoxdur.

Kod nümunələri: sadədən mürəkkəbə

expect/actual-ın sadə funksiyalardan tam hüquqlu siniflərə qədər praktik nümunələrini nəzərdən keçirək. Əsas hal — interfeysdə istifadə üçün platforma adını əldə etmək. Daha mürəkkəb nümunələr nativ yaddaşa giriş və platforma axınları ilə işi əhatə edir.

kotlin
// commonMain — təhlükəsiz yaddaş üçün expect sinifi
expect class PlatformStorage {
    fun save(key: String, value: String)
    fun get(key: String): String?
    fun remove(key: String)
}

// androidMain — Android-də actual
actual class PlatformStorage {
    private val prefs = AppContext.getSharedPreferences("secure", 0)

    actual fun save(key: String, value: String) { prefs.edit().putString(key, value).apply() }
    actual fun get(key: String): String? = prefs.getString(key, null)
    actual fun remove(key: String) { prefs.edit().remove(key).apply() }
}

Bu nümunədə PlatformStorage expect sinifi sadə açar-dəyər yaddaşının kontraktını müyyən edir. Android-də implementasiya SharedPreferences, iOS-da isə Keychain və ya NSUserDefaults istifadə edir. expect/actual sayəsində commonMain-dəki biznes məntiqi platforma implementasiyasını bilmədən save/get/remove çağırır.

kotlin
// iosMain — iOS-da Keychain ilə actual
actual class PlatformStorage {
    actual fun save(key: String, value: String) {
        val query = mapOf<String, Any>(
            kSecClass to kSecClassGenericPassword,
            kSecAttrAccount to key,
            kSecValueData to value.encodeToByteArray()
        )
        SecItemAdd(query, null)
    }

    actual fun get(key: String): String? {
        val query = mapOf<String, Any>(
            kSecClass to kSecClassGenericPassword,
            kSecAttrAccount to key,
            kSecReturnData to true
        )
        val result = mutableMapOf<String, Any>()
        return if (SecItemCopyMatching(query, result) == errSecSuccess)
            result[kSecValueData]?.toString()
        else null
    }

    actual fun remove(key: String) {
        val query = mapOf<String, Any>(
            kSecClass to kSecClassGenericPassword,
            kSecAttrAccount to key
        )
        SecItemDelete(query)
    }
}

expect/actual ən yaxşı təcrübələri

expect/actual API-ni dizayn edərkən bir neçə prinsipə riayət edilməlidir. Minimuma endirin expect bəyannamələrinin sayını — nə qədər çox ümumi kod varsa, dəstək bir o qədər asandır. expect/actual-ı yalnız platformalarda həqiqətən fərqlənən API-lər üçün istifadə edin. Qalan kod üçün interfeysləri fabrikalarla və ya dependency injection ilə tətbiq edin, bu testi asanlaşdırır.

expect bəyannamələrinin mövzu modulları üzrə qruplaşdırılması tövsiyə olunur, bir faylda qarışdırmaq əvəzinə. Məsələn, yaddaş üçün Storage.kt, ƏƏ ilə iş üçün Platform.kt və analitika üçün Analytics.kt expect bəyannamələri. Bu, KMM layihəsinin platforma səthində naviqasiyanı və anlayışı asanlaşdırır. Hər actual fayl müvafiq source set-də olmalıdır: androidMain, iosMain, desktopMain və s.

Default implementasiyalar actual fun-un ümumi koddan istifadə etdiyi expect fun vasitəsilə — geniş yayılmış anti-nümunədir. Platforma implementasiyası default-dan fərqlənmirsə, expect/actual lazım deyil. Belə hallarda commonMain-də sadə funksiyadan istifadə edin. Həmçinin mənasız getterlər üçün expect/actual-dan çəkinin — sabitlərlə expect val istifadə edin.

Layihədə kodun təşkili

expect/actual kodunun düzgün strukturu layihənin oxunaqlılığı üçün vacibdir. Hər expect/actual modulu vahid giriş nöqtəsinə malik olmalıdır. Təşkilat nümunəsi: commonMain/kotlin/com/project/platform expect bəyannamələrini ehtiva edir, androidMain/kotlin/com/project/platform — Android üçün actual-ı, iosMain/kotlin/com/project/platform — iOS üçün actual-ı. Fayl və paket adları expect və actual üçün uyğun olmalıdır ki, proqramçı müvafiq implementasiyanı tez tapa bilsin.

KMM-də expect/actual alternativləri

Interfeyslər platforma fabrikası ilə — expect/actual-ın əsas alternatividir. expect sinifi əvəzinə commonMain-də interfeys bəyan edilə bilər və platforma modullarında konkret siniflər yaradıla bilər. Fabrika və ya dependency injection konteyneri runtime-da düzgün implementasiyanı təmin edir. Bu yanaşma test üçün daha uyğundur, çünki interfeysi mock etmək olar.

Dependency Injection (Koin, Kodein) — daha çevik, lakin az məhsuldar yanaşmadır. DI konteyneri hər platforma üçün ayrıca konfiqurasiya olunur və ümumi koda platforma asılılıqlarını təmin edir. expect/actual-dan fərqli olaraq, injection runtime-da baş verir, bu da test üçün implementasiyaları dəyişməyə imkan verir. Digər tərəfdən, DI konfiqurasiya xətaları yalnız işə salma zamanı aşkar edilir, kompilyasiya mərhələsində yox.

YanaşmaKompilyasiya mərhələsində yoxlamaTest çevikliyiRuntime əlavə yükü
expect/actualTamAşağı (actual mock edilə bilməz)Sıfır (kompilyasiya əlaqəsi)
Interfeyslər + fabrikaQismənYüksək (mock edilə bilər)Minimal (virtual çağırış)
Dependency InjectionXeyr (runtime)YüksəkOrta (DI proksi)

expect/actual və alternativlər arasında seçim kontekstdən asılıdır. Kritik məhsuldarlıq üçün (oyun mühərrikləri, real-time emal) sıfır runtime yükü səbəbindən expect/actual üstünlüklüdür. Biznes məntiqi üçün (repozitoriyalar, use-case’lər) testi asanlaşdırmaq üçün DI ilə interfeyslərdən istifadə etmək daha yaxşıdır. Kombinə edilmiş yanaşma — aşağı səviyyəli platforma əməliyyatları üçün expect/actual və biznes məntiqi təbəqəsi üçün interfeyslər — əksər production KMM layihələrində tətbiq olunur.

Tez-tez verilən suallar

expect/actual’ın interfeyslərdən fərqi nədir?

expect/actual implementasiyanı virtual çağırışlar olmadan kompilyasiya mərhələsində birləşdirir, interfeyslər isə runtime-da. expect/actual bütün platformalar üçün implementasiyanın mövcudluğuna zəmanət verir, interfeyslər runtime yoxlamaları tələb edir.

expect/actual enum üçün istifadə oluna bilərmi?

Bəli, expect enum Kotlin 1.7-dən etibarən dəstəklənir. expect və actual enum-da bütün sabitlər uyğun olmalıdır. Müxtəlif platformalarda sabitlərin müxtəlif dəyərləri — kompilyasiya xətası.

actual implementasiyanı unutmaq nəyə gətirib çıxarar?

Kompilyator actual implementasiyası olmayan hər platforma üçün xəta verəcək. Bütün expect bəyannamələri üçün müvafiq actual implementasiyalar əlavə edilənə qədər layihə yığılmayacaq.

expect/actual eyni source set daxilində istifadə oluna bilərmi?

Xeyr, expect və actual müxtəlif source set’lərdə olmalıdır. expect — commonMain və ya aralıq source set-də, actual — platforma source set-ində. expect və actual-ın eyni source set-də yerləşdirilməsi kompilyasiya xətasıdır.

expect/actual kodunu necə test etmək olar?

expect/actual-ı test etmək üçün platforma test source set’ləri ilə commonTest istifadə edin. commonTest-də expect testləri və hər platforma üçün actual testləri yazın. İnteqrasiya testləri hər hədəf platformada ayrıca işə salınır.

Nəticə

  • expect/actual — kompilyator yoxlaması ilə platforma implementasiyaları üçün Kotlin Multiplatform-un əsas mexanizmi.
  • expect commonMain-də kontrakt bəyan edir, actual platforma source set-ində implementasiya təmin edir.
  • Bəyannamə növlərinə funksiyalar, siniflər, xassələr, enum sinifləri və typealias müxtəlif istifadə qaydaları ilə daxildir.
  • Kompilyator yoxlaması bütün hədəf platformalar üçün actual implementasiyaların mövcudluğuna zəmanət verir, runtime xətalarının qarşısını alır.
  • Tövsiyə olunur expect/actual-ı minimuma endirmək və biznes məntiqi üçün DI ilə interfeyslərdən istifadə etmək.
  • Kodun təşkili expect və actual üçün uyğun fayl və paket adları ilə vahid olmalıdır.
  • Aşağı səviyyəli platforma əməliyyatları (yaddaş, fayl sistemi, sensorlar) üçün expect/actual istifadə edin — bu sıfır runtime yükü təmin edir.

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun