Ce face external
O funcție external nu are corp: îi spui compilatorului că implementarea există în altă parte. Pe JVM, external este echivalentul lui native din Java: funcția este scrisă în C sau C++, compilată într-o bibliotecă (.so, .dll, .dylib) și încărcată cu System.loadLibrary("nume"). Legătura se face prin JNI (Java Native Interface), după numele clasei și al funcției.
Dacă apelezi funcția fără să fi încărcat biblioteca, JVM aruncă UnsatisfiedLinkError. În Kotlin/JS, external declară funcții, clase și variabile care există deja în JavaScript (în browser sau într-un pachet npm), ca să le poți apela cu verificare de tipuri.
Pentru majoritatea programelor nu ai nevoie de external. Pe JVM se folosește pentru biblioteci native (criptografie, procesare video, drivere), iar în Kotlin/Native interoperabilitatea cu C se face prin cinterop, nu prin external.
Exemple
Exemplul 1: Funcție nativă fără bibliotecă încărcată
Declarația compilează, dar biblioteca nativă nu există, deci apelul aruncă UnsatisfiedLinkError, prins aici ca programul să explice ce s-a întâmplat.
external fun calculeazaHash(text: String): Long
fun main() {
try {
println(calculeazaHash("Ana"))
} catch (e: UnsatisfiedLinkError) {
println("Biblioteca nativă lipsește: ${e.message}")
}
}
Rezultat
Biblioteca nativă lipsește: 'long MainKt.calculeazaHash(java.lang.String)'
Exemplul 2: Cu bibliotecă JNI (nu rulează aici)
Partea în C implementează funcția cu numele cerut de JNI (Java_ + clasă + funcție). Kotlin încarcă biblioteca o dată, la pornire, apoi apelează funcția ca pe oricare alta.
// hash.c, compilat în libhash.so:
// JNIEXPORT jlong JNICALL Java_MainKt_calculeazaHash(JNIEnv *env, jclass cls, jstring text) { ... }
external fun calculeazaHash(text: String): Long
fun main() {
System.loadLibrary("hash") // caută libhash.so în java.library.path
println("Hash pentru Ana: ${calculeazaHash("Ana")}")
}
Rezultat (cu libhash.so compilată și java -Djava.library.path=.)
Hash pentru Ana: 2045623
Greșeli frecvente
- Un corp pentru o funcție
external: eroareexternal declaration cannot have a body. - Numele funcției C nu corespunde cu clasa generată de Kotlin: funcțiile din
main.ktstau în clasaMainKt, deci numele JNI esteJava_MainKt_...; altfel apareUnsatisfiedLinkErrorchiar dacă biblioteca e încărcată. - Uitarea lui
System.loadLibraryînainte de primul apel.
Comenzi înrudite
expect și actual: expect declară în codul comun ceva ce fiecare platformă (JVM, Android, iOS, JS) implementează separat cu actual.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.kotlinc: Compilatorul Kotlin din linia de comandă: transformă fișierele .kt într-un program care rulează pe JVM.fun: fun declară o funcție: un bloc de cod cu nume, care primește parametri și poate returna un rezultat.