Bỏ qua để đến nội dung

🔍 Scope Functions

🎯 Mục tiêu: Nắm vững 5 scope functions: let, run, with, apply, also - công cụ viết code Kotlin idiomatic.


Scope functions tạo scope tạm thời để thao tác với object. Chúng khác nhau ở:

  1. Cách tham chiếu object: this (context object) hoặc it (lambda argument)
  2. 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

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) // HELLO
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) }

Reference: this | Returns: Lambda result

val result = "hello".run {
println("Length: $length") // this.length
uppercase() // return value
}
println(result) // HELLO
val service = NetworkService().run {
port = 8080
timeout = 30000
connect() // Returns connection result
}
val hexString = run {
val red = 255
val green = 128
val blue = 0
"#${red.toString(16)}${green.toString(16)}${blue.toString(16)}"
}

Reference: this | Returns: Lambda result

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("List: $this")
println("Size: $size")
println("First: ${first()}")
}
val config = with(Configuration()) {
host = "localhost"
port = 8080
timeout = 5000
this // Return config
}

Reference: this | Returns: Object itself

val person = Person().apply {
name = "Alice"
age = 25
city = "Hanoi"
}
// person đã được config và trả về
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
}

Reference: it | Returns: Object itself

val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("Before: $it") }
.add("four")
.also { println("Add successful") }
val user = createUser()
.also { println("Created user: ${it.name}") }
.also { validateUser(it) }
.also { saveToDatabase(it) }

graph TD
A[Need scope function?] --> B{Return value?}
B -->|Object itself| C{Reference style?}
B -->|Lambda result| D{Reference style?}
C -->|this| E[apply]
C -->|it| F[also]
D -->|this| G{Has receiver?}
D -->|it| H[let]
G -->|Yes| I[run]
G -->|No| J[with]
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

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à also

Lời giải:

fun createUser() = User().apply {
name = "Alice"
age = 25
}.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}")
}

// 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) }


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 this vs it reference
  • Phân biệt return object vs return lambda result
  • Chọn đúng scope function cho use case
  • Sử dụng let cho null check
  • Sử dụng apply cho object initialization

Tiếp theo: Collections - List