Ang scope functions sa Kotlin ay limang function ng standard library (let, run, with, apply, also) na nagpapatupad ng block ng code sa konteksto ng isang object. Nagkakaiba sila sa paraan ng pag-access sa object (sa pamamagitan ng it o this) at sa return value (context object o resulta ng lambda). Ayon sa dokumentasyon ng Kotlin (2026), ang tamang pagpili ng scope function ay nagbabawas ng boilerplate code ng 25–40%. Scope functions ay tumutulong sa pagsulat ng initialization, configuration at transformation ng mga object sa deklaratibong istilo.
Mga pangunahing punto
Scope functions (mga function ng saklaw) — ay isang set ng limang function (let, run, with, apply, also) na nakapaloob sa standard library ng Kotlin. Bawat isa ay tumatanggap ng lambda at pansamantalang binabago ang saklaw ng visibility upang sa loob ng lambda ang code ay naisasagawa sa konteksto ng isang partikular na object. Ito ay umiiwas sa pag-uulit ng pangalan ng object sa maraming tawag at nag-grupo ng mga kaugnay na operasyon sa isang block.
Dalawang pangunahing katangian ang nagpapakilala sa scope functions: paraan ng pag-access sa context object (sa pamamagitan ng this o it) at ang return value (ang context object mismo o resulta ng lambda). Ang pag-access sa pamamagitan ng this ay ginagawang implicit receiver ang object — ang mga method at property ay tinatawag nang walang prefix. Ang pag-access sa pamamagitan ng it ay nagpapasa ng object bilang eksplisitong parameter ng lambda. Ang pagbabalik ng object ay nagbibigay-daan sa pagbuo ng mga chain, pagbabalik ng resulta — pagtatalaga ng transformed value.
Sa kasaysayan, ang scope functions ay lumitaw bilang kapalit ng klasikong pattern na Builder at mga pansamantalang variable para sa initialization. Sa halip na gumawa ng hiwalay na builder class, ang programmer ay sumusulat ng apply { property1 = ...; property2 = ... }. Ito ay nagbabawas ng dami ng code at ginagawang mas nababasa ang initialization. Sa ecosystem ng Kotlin, ang scope functions ay ginagamit sa lahat ng frameworks at library bilang standard na idyoma ng wika.
Ang pagpili ng tamang scope function ay natutukoy ng dalawang tanong: gusto mo bang gumamit ng this o it para sa pag-access sa object, at gusto mo bang ibalik ang object mismo o ang resulta ng lambda. Ang kombinasyon ng dalawang binary na katangian ay nagbibigay ng apat na posibleng variant, at ang with ay may espesyal na lugar bilang tanging function na hindi extension.
| Function | Access | Return | Extension? | Karaniwang scenario |
|---|---|---|---|---|
| let | it | resulta ng lambda | oo | Transformation, null check |
| run | this | resulta ng lambda | oo | Computation na may konteksto |
| with | this | resulta ng lambda | hindi | Pag-grupo ng mga tawag |
| apply | this | context object | oo | Initialization ng mga property |
| also | it | context object | oo | Side effects, pag-log |
Para sa configuration ng object nang walang pagbabalik ng bagong value gamitin ang apply (access sa pamamagitan ng this) o also (access sa pamamagitan ng it). Para sa pagkalkula ng bagong value batay sa object gamitin ang let (access sa pamamagitan ng it) o run (access sa pamamagitan ng this). Para sa pag-grupo ng mga tawag nang walang chain gamitin ang with. Ang pagsunod sa scheme na ito ay ginagawang predictable ang code para sa ibang developers na pamilyar sa Kotlin.
apply — scope function na nagbabalik ng context object at nagbibigay ng access dito sa pamamagitan ng this. Ito ay perpektong tool para sa initialization ng mga property ng object pagkatapos ng paggawa. Sa loob ng apply block, ang mga property ay maaaring itakda nang hindi inuulit ang pangalan ng object. Ang method ay nagbabalik ng object mismo, na nagpapahintulot sa pag-embed ng apply sa mga chain o paggamit sa mga initializer.
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
}
Sa listing, apply ay nagco-configure ng ServerConfig, direktang ina-access ang mga property sa pamamagitan ng this (this ay hindi kasama). Kung walang apply, kailangan isulat ang config.host = ..., config.port = ... — tatlong paulit-ulit na reference sa parehong variable. Ang pagbabalik ng object ay nagpapahintulot na i-save ang resulta ng configuration sa val config. also, hindi katulad ng apply, ay nagpapasa ng object sa pamamagitan ng it at angkop para sa side effects.
fun saveUser(user: User) {
validate(user).also { result ->
println("Resulta ng validation: $result")
}
val savedUser = user.also {
log("Saving user ${it.id}")
database.save(it)
}
}
Sa halimbawa, also ay ginagamit para sa pag-log — sa pagbabalik ng orihinal na object, ito ay nagsasagawa ng side effect (pag-print ng mensahe) nang hindi binabago ang object. Ito ay isang chain: validate(user) ay nagbabalik ng User, also ay nagla-log ng resulta at nagpapasa ng user. also ay kapaki-pakinabang din para sa pagdagdag ng mga elemento sa collections o debugging sa gitna ng chain ng transformation.
let — scope function na nagbabalik ng resulta ng lambda at nagpapasa ng konteksto sa pamamagitan ng it. Ito ang pangunahing function para sa null-safe transformations: kung ang object ay nullable, ang kombinasyon na ?.let { } ay magpapatupad ng block lamang sa non-null na value. let ay ginagamit din para sa paglilimita ng saklaw ng visibility ng pansamantalang variable at map-like transformations mula sa isang type papunta sa isa pa.
fun findUser(id: Int): User?
val displayName = findUser(42)?.let { user ->
"${user.name} (${user.email})"
} ?: "Unknown user"
// let na may transformation ng koleksyon
val numbers = listOf("1", "2", "3")
val parsed = numbers.firstOrNull()?.let {
it.toIntOrNull()
} ?: 0
Sa unang halimbawa, let ay tinatawag sa pamamagitan ng ?. — ang block ay isinasagawa lamang kung ang findUser ay nagbalik ng non-null. Ang lambda ay tumatanggap ng user sa pamamagitan ng it (maaaring palitan ng pangalan para sa kalinawan) at nagbabalik ng formatted string. Kung ang user ay hindi natagpuan — ang Elvis operator ?: ay nagbibigay ng default na value. Sa pangalawang halimbawa, let ay nagko-convert ng string sa numero na may potensyal na null.
run — analog ng let na may access sa pamamagitan ng this, na nagbabalik ng resulta ng lambda. run ay maginhawa para sa computation kung saan kinakailangan ang konteksto ng object ngunit ang bagong value ay ibinabalik. Ang tawag na run() nang walang object (tulad ng run { ... }) ay lumilikha ng pansamantalang saklaw ng visibility para sa mga variable. with — non-extension na may access sa pamamagitan ng this, angkop para sa pag-grupo ng mga tawag nang walang chain.
// run bilang context-driven na computation
val transformed = listOf(1, 2, 3).run {
filter { it > 1 }.map { it * 10 }
}
println(transformed) // [20, 30]
// with para sa pag-grupo ng mga tawag
val info = with(StringBuilder()) {
append("Name: ")
append("Alice")
toString()
}
Sa halimbawa, run sa listahan ay nagbabalik ng resulta ng pag-filter at pag-ma-map — ang transformation mismo, hindi ang listahan. with ay tumatanggap ng StringBuilder bilang argument (hindi sa pamamagitan ng tuldok) at sa loob ay gumagana sa this: append, append, toString. Ang resulta ng with — ang string info. Ang pagpili sa pagitan ng run at with ay madalas subjective, ngunit ang with ay mas gusto kapag ang object ay ipinapasa mula sa ibang lugar nang walang chain ng tawag.
with ay naiiba sa ibang scope functions dahil ito ay hindi extension function. Ito ay tumatanggap ng object bilang unang argument, at lambda bilang pangalawang argument. Sa loob ng lambda, ang object ay maa-access sa pamamagitan ng this. with ay maginhawa para sa pag-grupo ng mga method calls ng object nang hindi nagse-save ng resulta o kapag kinakailangan pansamantalang “pumasok” sa konteksto para magbasa ng maraming property.
val user = User("Alice", "alice@example.com", "Admin")
val summary = with(user) {
"User $name has role $role and email $email"
}
println(summary)
// with para sa initialization ng UI component
with(TextView(context)) {
text = "Hello"
textSize = 18.0f
setTextColor(Color.BLUE)
}
Sa unang halimbawa, with ay bumubuo ng string summary, direktang ina-access ang mga property ng user sa pamamagitan ng this. Kung walang with, kailangan isulat ang “User ${user.name} has role ${user.role}” — paulit-ulit na pagbanggit ng user. Sa pangalawang halimbawa, with ay nag-grupo ng configuration ng TextView: lahat ng method at property ay tinatawag sa isang object nang walang pag-uulit. Disadvantage ng with — hindi magagamit sa chain, dahil hindi ito extension at hindi nagbabalik ng context object.
Mga Madalas Itanong
Gamitin ang apply — ito ay nagbabalik ng object at nagbibigay ng access sa pamamagitan ng this, na nagpapahintulot sa pag-set ng mga property nang hindi inuulit ang pangalan ng object. also ay angkop kung kailangan ang eksplisitong parameter it para sa pagkakaiba mula sa mga property ng object.
let ay nagpapasa ng konteksto sa pamamagitan ng it (eksplisitong parameter), run — sa pamamagitan ng this (implicit receiver). let ay maginhawa para sa null checks at transformations, run — para sa computation na may konteksto. Pareho silang nagbabalik ng resulta ng lambda.
with ay hindi extension — ito ay tumatanggap ng object bilang argument. Gamitin ang with para sa pag-grupo ng mga tawag kapag hindi kailangan ang chain. apply — extension na nagbabalik ng object, maginhawa sa mga initializer at builder patterns.
Oo, ngunit mag-ingat sa this — ang nested this ay nagdudulot ng kalituhan. Gumamit ng let o also na may eksplisitong pangalan para sa nested contexts upang maiwasan ang kalabuan sa pagtukoy sa panlabas na object.
Lahat ng scope functions ay inline, kaya hindi sila lumilikha ng overhead para sa anonymous classes. Ang pagkakaiba sa performance sa pagitan nila ay bale-wala. Ang pagpili ay dapat batay sa readability at conventions, hindi sa bilis.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din