Scope functions di Kotlin adalah lima fungsi pustaka standar (let, run, with, apply, also) yang menjalankan blok kode dalam konteks sebuah objek. Mereka berbeda dalam cara mengakses objek (melalui it atau this) dan nilai yang dikembalikan (objek konteks atau hasil lambda). Menurut dokumentasi Kotlin (2026), pemilihan scope function yang tepat mengurangi kode boilerplate sebesar 25–40%. Scope functions membantu menulis inisialisasi, konfigurasi, dan transformasi objek dalam gaya deklaratif.
Poin utama
Scope functions (fungsi lingkup) — adalah kumpulan lima fungsi (let, run, with, apply, also) yang tertanam dalam pustaka standar Kotlin. Masing-masing menerima lambda dan untuk sementara mengubah lingkup visibilitas sehingga di dalam lambda kode dijalankan dalam konteks objek tertentu. Ini menghindari pengulangan nama objek pada panggilan berganda dan mengelompokkan operasi terkait dalam satu blok.
Dua karakteristik kunci membedakan scope functions: cara mengakses objek konteks (melalui this atau it) dan nilai yang dikembalikan (objek konteks itu sendiri atau hasil lambda). Akses melalui this menjadikan objek penerima implisit — metode dan properti dipanggil tanpa prefiks. Akses melalui it mengirim objek sebagai parameter eksplisit lambda. Mengembalikan objek memungkinkan pembangunan rantai, mengembalikan hasil — penugasan nilai yang ditransformasi.
Secara historis, scope functions muncul sebagai pengganti pola klasik Builder dan variabel sementara untuk inisialisasi. Alih-alih membuat kelas builder terpisah, pengembang menulis apply { properti1 = ...; properti2 = ... }. Ini mengurangi jumlah kode dan membuat inisialisasi lebih mudah dibaca. Dalam ekosistem Kotlin, scope functions digunakan di semua framework dan pustaka sebagai idiom standar bahasa.
Pemilihan scope function yang tepat ditentukan oleh dua pertanyaan: apakah Anda ingin menggunakan this atau it untuk mengakses objek, dan apakah Anda ingin mengembalikan objek itu sendiri atau hasil lambda. Kombinasi dua karakteristik biner memberikan empat kemungkinan varian, dan with menempati posisi khusus sebagai satu-satunya fungsi yang bukan ekstensi.
| Fungsi | Akses | Kembalian | Ekstensi? | Skenario tipikal |
|---|---|---|---|---|
| let | it | hasil lambda | ya | Transformasi, pemeriksaan null |
| run | this | hasil lambda | ya | Perhitungan dengan konteks |
| with | this | hasil lambda | tidak | Pengelompokan panggilan |
| apply | this | objek konteks | ya | Inisialisasi properti |
| also | it | objek konteks | ya | Efek samping, pencatatan |
Untuk konfigurasi objek tanpa mengembalikan nilai baru gunakan apply (akses melalui this) atau also (akses melalui it). Untuk menghitung nilai baru berdasarkan objek gunakan let (akses melalui it) atau run (akses melalui this). Untuk mengelompokkan panggilan tanpa rantai gunakan with. Mengikuti skema ini membuat kode dapat diprediksi bagi pengembang lain yang akrab dengan Kotlin.
apply — scope function yang mengembalikan objek konteks dan menyediakan akses ke sana melalui this. Ini adalah alat ideal untuk inisialisasi properti objek setelah pembuatan. Di dalam blok apply, properti dapat diatur tanpa mengulangi nama objek. Metode mengembalikan objek itu sendiri, memungkinkan penyematan apply dalam rantai atau penggunaan dalam inisialisator.
data class ServerConfig(
var host: String = "localhost",
var port: Int = 8080,
var useTls: Boolean = false
)
val config = ServerConfig().apply {
host = "api.example.com"
port = 443
useTls = true
}
Dalam listing, apply mengonfigurasi ServerConfig, mengakses properti langsung melalui this (this dihilangkan). Tanpa apply harus menulis config.host = ..., config.port = ... — tiga referensi berulang ke variabel yang sama. Mengembalikan objek memungkinkan menyimpan hasil konfigurasi dalam val config. also, tidak seperti apply, mengirim objek melalui it dan cocok untuk efek samping.
fun saveUser(user: User) {
validate(user).also { result ->
println("Hasil validasi: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
Dalam contoh, also digunakan untuk pencatatan — dengan mengembalikan objek asli, ia melakukan efek samping (mencetak pesan) tanpa mengubah objek. Ini adalah rantai: validate(user) mengembalikan User, also mencatat hasil dan meneruskan pengguna. also juga berguna untuk menambahkan elemen ke koleksi atau debugging di tengah rantai transformasi.
let — scope function yang mengembalikan hasil lambda dan mengirim konteks melalui it. Ini adalah fungsi utama untuk transformasi null-safe: jika objek nullable, kombinasi ?.let { } akan menjalankan blok hanya pada nilai non-null. let juga digunakan untuk membatasi lingkup visibilitas variabel sementara dan transformasi mirip map dari satu tipe ke tipe lain.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let dengan transformasi koleksi
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
Dalam contoh pertama, let dipanggil melalui ?. — blok dijalankan hanya jika findUser mengembalikan non-null. Lambda menerima user melalui it (dapat dinamai ulang untuk kejelasan) dan mengembalikan string yang diformat. Jika pengguna tidak ditemukan — operator Elvis ?: memberikan nilai default. Dalam contoh kedua, let mengubah string menjadi angka dengan potensi null.
run — analog let dengan akses melalui this, yang mengembalikan hasil lambda. run nyaman untuk perhitungan di mana konteks objek diperlukan tetapi nilai baru dikembalikan. Panggilan run() tanpa objek (seperti run { ... }) menciptakan lingkup visibilitas sementara untuk variabel. with — non-ekstensi dengan akses melalui this, cocok untuk mengelompokkan panggilan tanpa rantai.
// run sebagai perhitungan berbasis konteks
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with untuk pengelompokan panggilan
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
Dalam contoh, run pada daftar mengembalikan hasil pemfilteran dan pemetaan — transformasi itu sendiri, bukan daftar. with menerima StringBuilder sebagai argumen (bukan melalui titik) dan di dalamnya bekerja dengan this: append, append, toString. Hasil with — string info. Pilihan antara run dan with sering subyektif, tetapi with lebih disukai ketika objek dikirim dari tempat lain tanpa rantai panggilan.
with berbeda dari scope functions lainnya karena bukan fungsi ekstensi. Ia menerima objek sebagai argumen pertama dan lambda sebagai argumen kedua. Di dalam lambda, objek dapat diakses melalui this. with nyaman untuk mengelompokkan panggilan metode objek tanpa menyimpan hasil atau ketika diperlukan untuk sementara “masuk” ke dalam konteks untuk membaca beberapa properti.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with untuk inisialisasi komponen UI
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
Dalam contoh pertama, with membentuk string summary, mengakses properti user langsung melalui this. Tanpa with harus menulis “User ${user.name} has role ${user.role}” — pengulangan user berkali-kali. Dalam contoh kedua, with mengelompokkan konfigurasi TextView: semua metode dan properti dipanggil pada satu objek tanpa pengulangan. Kekurangan with — ketidakmampuan menggunakan dalam rantai, karena bukan ekstensi dan tidak mengembalikan objek konteks.
Pertanyaan yang sering diajukan
Gunakan apply — ia mengembalikan objek dan menyediakan akses melalui this, memungkinkan pengaturan properti tanpa mengulangi nama objek. also cocok jika parameter it eksplisit diperlukan untuk membedakan dari properti objek.
let mengirim konteks melalui it (parameter eksplisit), run — melalui this (penerima implisit). let nyaman untuk pemeriksaan null dan transformasi, run — untuk perhitungan dengan konteks. Keduanya mengembalikan hasil lambda.
with bukan ekstensi — ia menerima objek sebagai argumen. Gunakan with untuk mengelompokkan panggilan ketika rantai tidak diperlukan. apply — ekstensi yang mengembalikan objek, nyaman dalam inisialisator dan pola builder.
Ya, tetapi hati-hati dengan this — this bersarang menyebabkan kebingungan. Gunakan let atau also dengan nama eksplisit untuk konteks bersarang untuk menghindari ambiguitas saat merujuk ke objek eksternal.
Semua scope functions adalah inline, sehingga tidak menciptakan overhead untuk kelas anonim. Perbedaan performa di antara mereka dapat diabaikan. Pemilihan harus didasarkan pada keterbacaan dan konvensi, bukan kecepatan.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga