Scope Functions trong Kotlin
🎯 Mục tiêu: Nắm vững 5 scope functions:
let,run,with,apply,also- công cụ viết code Kotlin idiomatic.
💡 Tổng quan
Scope functions tạo scope tạm thời để thao tác với object. Chúng khác nhau ở:
- Cách tham chiếu object:
this(context object) hoặcit(lambda argument) - Giá trị trả về: Object gốc hoặc kết quả lambda
| Function | Reference | Returns | Use case |
|---|---|---|---|
let | it | Lambda result | Null checks, scoping |
run | this | Lambda result | Object config + compute |
with | this | Lambda result | Group operations |
apply | this | Object | Object configuration |
also | it | Object | Side effects |
📝 let
Reference: it | Returns: Lambda result
// Null check
val name: String? = "Kotlin"
name?.let {
println("Name length: ${it.length}")
}
// Scoping transformation
val result = "hello".let {
println("Original: $it")
it.uppercase()
}
println(result) // HELLOUse case: Chain transformations
val numbers = mutableListOf("one", "two", "three")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)
// Hoặc dùng let cho clarity
numbers
.map { it.length }
.filter { it > 3 }
.let { println(it) }🔄 run
Reference: this | Returns: Lambda result
val result = "hello".run {
println("Length: $length") // this.length
uppercase() // return value
}
println(result) // HELLOUse case: Object config + compute result
val service = NetworkService().run {
port = 8080
timeout = 30000
connect() // Returns connection result
}run không có receiver
val hexString = run {
val red = 255
val green = 128
val blue = 0
"#${red.toString(16)}${green.toString(16)}${blue.toString(16)}"
}🔗 with
Reference: this | Returns: Lambda result
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("List: $this")
println("Size: $size")
println("First: ${first()}")
}Use case: Group operations on object
val config = with(Configuration()) {
host = "localhost"
port = 8080
timeout = 5000
this // Return config
}[!NOTE]
withkhông phải extension function, syntax:with(object) { }
🛠️ apply
Reference: this | Returns: Object itself
val person = Person().apply {
name = "Alice"
age = 25
city = "Hanoi"
}
// person đã được config và trả vềUse case: Builder pattern, object initialization
val intent = Intent(this, MainActivity::class.java).apply {
putExtra("USER_ID", 123)
putExtra("USER_NAME", "Alice")
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val textView = TextView(context).apply {
text = "Hello"
textSize = 16f
setTextColor(Color.BLACK)
gravity = Gravity.CENTER
}👀 also
Reference: it | Returns: Object itself
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("Before: $it") }
.add("four")
.also { println("Add successful") }Use case: Logging, debugging, side effects
val user = createUser()
.also { println("Created user: ${it.name}") }
.also { validateUser(it) }
.also { saveToDatabase(it) }🎯 Chọn Scope Function phù hợp
Quy tắc đơn giản
| Mục đích | Dùng |
|---|---|
| Null check & transform | let |
| Object initialization | apply |
| Side effects/logging | also |
| Run code block, get result | run |
| Group operations on object | with |
🛠️ Thực hành
Bài tập 1: Refactor code với scope functions
// Before
fun createUser(): User {
val user = User()
user.name = "Alice"
user.age = 25
user.email = "[email protected]"
println("Created user: $user")
return user
}
// TODO: Refactor dùng apply và alsoLời giải:
fun createUser() = User().apply {
name = "Alice"
age = 25
email = "[email protected]"
}.also {
println("Created user: $it")
}Bài tập 2: Null-safe operation chain
fun main() {
val user: User? = findUser(123)
// TODO: Nếu user exists, validate và save
}Lời giải:
fun main() {
val user: User? = findUser(123)
user?.let { u ->
validateUser(u)
}?.run {
saveToDatabase(this)
sendWelcomeEmail(this.email)
"User saved successfully"
} ?: "User not found"
}Bài tập 3: Builder pattern
fun main() {
// TODO: Tạo request với apply
}Lời giải:
val request = HttpRequest().apply {
url = "https://api.example.com/users"
method = "POST"
headers["Content-Type"] = "application/json"
headers["Authorization"] = "Bearer token123"
body = """{"name": "Alice", "age": 25}"""
}.also {
println("Sending request to ${it.url}")
}📱 Trong Android
// View configuration with apply
val button = Button(context).apply {
text = "Click Me"
setTextColor(Color.WHITE)
setBackgroundColor(Color.BLUE)
setOnClickListener { handleClick() }
}
// Intent with apply
startActivity(Intent(this, DetailActivity::class.java).apply {
putExtra("ITEM_ID", item.id)
putExtra("ITEM_NAME", item.name)
})
// Null-safe with let
user?.let { currentUser ->
binding.nameText.text = currentUser.name
binding.emailText.text = currentUser.email
binding.avatarImage.load(currentUser.avatarUrl)
}
// Logging with also
viewModel.loadData()
.also { Log.d(TAG, "Data loaded: ${it.size} items") }
.also { analytics.trackDataLoad(it.size) }⚠️ Lưu ý quan trọng
[!WARNING] Không lồng quá nhiều scope functions:
// ❌ Khó đọc obj.let { it.run { this.apply { also { } } } } // ✅ Tách thành steps rõ ràng val processed = obj.let { transform(it) } processed.apply { configure() }
[!TIP] Khi
thisconflicts, dùngitversion:class MyClass { fun process() { // this đã là MyClass someObject.also { obj -> // Dùng also thay vì apply obj.property = this.value } } }
✅ Checklist - Tự kiểm tra
Sau bài học này, bạn có thể:
- Biết 5 scope functions:
let,run,with,apply,also - Phân biệt
thisvsitreference - Phân biệt return object vs return lambda result
- Chọn đúng scope function cho use case
- Sử dụng
letcho null check - Sử dụng
applycho object initialization
Tiếp theo: Collections - List
Last updated on