Fungsi Lokal dan Top-Level

Fungsi di dalam fungsi dan fungsi tingkat berkas tanpa kelas.

Daftar isi

Kotlin memungkinkan fungsi dideklarasikan tanpa kelas sama sekali, baik di tingkat berkas maupun di dalam fungsi lain. Fungsi lokal menampung langkah bantu yang hanya bermakna bagi fungsi pembungkusnya, sedangkan fungsi top-level memuat logika yang dapat dipakai di seluruh berkas. Topik ini membahas keduanya, akses variabel dari fungsi lokal, serta kesalahan urutan deklarasi yang sering terjadi.

Fungsi lokal#

Fungsi lokal dideklarasikan di dalam tubuh fungsi lain dan hanya dapat dipanggil dari fungsi tersebut. Deklarasi seperti ini cocok untuk langkah bantu yang berulang di dalam satu fungsi, tanpa memperluas ruang nama tingkat berkas. Program berikut memakai dua fungsi lokal, yaitu bersihkan untuk penghitung kata dan normal untuk statistik suhu.

kotlin main.kt
fun hitungKata(teks: String): Int {
    // fungsi lokal: hanya terlihat di dalam hitungKata
    fun bersihkan(kata: String): String {
        return kata.trim().lowercase()
    }

    var jumlah = 0
    for (kata in teks.split(" ")) {
        if (bersihkan(kata).isNotEmpty()) {
            jumlah += 1
        }
    }
    return jumlah
}

fun hitungSuhuNormal(dataSuhu: List<Int>): Int {
    val batas = 20
    // fungsi lokal membaca variabel batas dari fungsi pembungkusnya
    fun normal(suhu: Int): Boolean {
        return suhu >= batas
    }

    var jumlah = 0
    for (suhu in dataSuhu) {
        if (normal(suhu)) {
            jumlah += 1
        }
    }
    return jumlah
}

fun main() {
    val kalimat = "  Kotlin berjalan di atas JVM  "
    println("Jumlah kata: ${hitungKata(kalimat)}")
    println("Suhu normal: ${hitungSuhuNormal(listOf(18, 24, 30, 19))}")
}
bash
# compiler Kotlin dan pustaka standar yang dipakai jalur ini
export PATH=/home/kal/my-project/tools/kotlinc/bin:/home/kal/my-project/tools/jdk-merged/bin:$PATH
export STDLIB=/home/kal/my-project/tools/kotlinc/lib/kotlin-stdlib.jar
# kompilasi berkas main.kt menjadi out.jar, lalu jalankan programnya
kotlinc main.kt -d out.jar && java -cp "out.jar:$STDLIB" MainKt
text Keluaran
Jumlah kata: 5
Suhu normal: 2

Fungsi bersihkan menghapus spasi di awal dan akhir kata lalu mengubahnya menjadi huruf kecil, sehingga spasi ganda pada kalimat tidak terhitung sebagai kata dan hasil penghitungannya tepat 5. Fungsi normal memeriksa suhu terhadap batas yang ditetapkan, dan keluaran Suhu normal: 2 menyatakan bahwa dua nilai dari 18, 24, 30, dan 19 memenuhi syarat tersebut. Kedua fungsi bantu itu tidak terlihat di luar fungsi pembungkusnya, sehingga tidak menambah nama baru pada tingkat berkas.

Akses variabel fungsi pembungkus#

Fungsi lokal membaca variabel dan parameter milik fungsi pembungkusnya secara langsung. Pada hitungSuhuNormal, fungsi normal membaca variabel batas yang dideklarasikan di tubuh hitungSuhuNormal, sehingga nilai batas tidak perlu dikirim sebagai parameter tambahan. Kemampuan ini sering disebut closure, yaitu fungsi yang mengikat lingkungan variabel tempat ia dideklarasikan. Variabel yang ditangkap tetap dapat digunakan selama fungsi lokalnya dapat dipanggil, dan pembacaan nilainya mengikuti keadaan terakhir variabel tersebut.

Apabila langkah bantu tidak bergantung pada variabel pembungkusnya, fungsi top-level biasanya lebih tepat karena dapat diuji dan dipanggil ulang tanpa membawa konteks fungsi lain. Fungsi lokal paling bernilai ketika logikanya membutuhkan keadaan milik pembungkusnya dan tidak berguna bagi bagian program lain. Pertimbangan ini menjaga ukuran fungsi pembungkus tetap wajar, karena fungsi lokal yang terlalu banyak justru menyulitkan pembacaan.

Fungsi top-level#

Fungsi top-level dideklarasikan langsung di tingkat berkas, tanpa dibungkus kelas apa pun. Bentuk ini berbeda dari Java yang mewajibkan setiap metode berada di dalam kelas, sehingga Kotlin tidak memerlukan kelas pembungkus hanya untuk menampung fungsi. Fungsi main pada seluruh program dalam jalur ini adalah contoh fungsi top-level, dan fungsi top-level dari berkas lain dapat dipanggil setelah nama fungsinya diimpor.

Di belakang layar, compiler tetap membentuk sebuah kelas untuk menampung fungsi top-level. Kelas tersebut dinamai dari nama berkasnya, sehingga fungsi-fungsi pada main.kt menjadi anggota kelas MainKt. Daftar isi berkas out.jar hasil kompilasi program di atas menunjukkan kelas itu secara nyata.

bash
# tampilkan isi berkas out.jar hasil kompilasi main.kt
jar tf out.jar
text Keluaran
META-INF/MANIFEST.MF
MainKt.class
META-INF/main.kotlin_module

Entri MainKt.class pada keluaran adalah kelas yang menampung main, hitungKata, dan hitungSuhuNormal. Detail penamaan ini penting ketika fungsi top-level dipanggil dari Java, karena pemanggil dari Java menunjuk kelas tersebut secara langsung. Anotasi @file:JvmName dapat mengganti nama kelasnya apabila nama bawaan kurang sesuai.

Kesalahan umum#

Fungsi lokal wajib dideklarasikan sebelum dipanggil, karena compiler memproses tubuh fungsi secara berurutan. Kesalahan urutan ini menghasilkan pesan referensi yang tidak ditemukan. Berkas berikut memanggil sapa sebelum deklarasinya ditulis.

kotlin urutan.kt
fun coba() {
    sapa()
    fun sapa() {
        println("Halo")
    }
}
bash
# kompilasi berkas urutan.kt untuk melihat pesan error dari compiler
kotlinc urutan.kt -d urutan.jar
text Keluaran
urutan.kt:2:5: error: unresolved reference 'sapa'.
    sapa()
    ^^^^

Pesan error unresolved reference 'sapa' muncul karena pada baris pemanggilan, nama sapa belum dikenal compiler. Perbaikannya adalah memindahkan deklarasi sapa ke atas pemanggilannya di dalam fungsi yang sama. Aturan ini hanya berlaku pada fungsi lokal, sedangkan fungsi top-level bebas diletakkan di bagian mana pun dalam berkas sebagaimana dinyatakan pada catatan di bagian sebelumnya.

Ringkasan#

  • Fungsi lokal hanya terlihat di dalam fungsi pembungkusnya dan dapat membaca variabel milik pembungkus tersebut.
  • Fungsi top-level hidup di tingkat berkas tanpa kelas dan dikompilasi menjadi anggota kelas yang dinamai dari berkasnya.
  • Fungsi lokal wajib dideklarasikan sebelum dipanggil, sedangkan fungsi top-level bebas urutannya dalam satu berkas.

Referensi#