🔍 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.
💡 Tổng quan
Phần tiêu đề “💡 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
Phần tiêu đề “📝 let”Reference: it | Returns: Lambda result
// Null checkval name: String? = "Kotlin"name?.let { println("Name length: ${it.length}")}
// Scoping transformationval result = "hello".let { println("Original: $it") it.uppercase()}println(result) // HELLOUse case: Chain transformations
Phần tiêu đề “Use 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 claritynumbers .map { it.length } .filter { it > 3 } .let { println(it) }🔄 run
Phần tiêu đề “🔄 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
Phần tiêu đề “Use case: Object config + compute result”val service = NetworkService().run { port = 8080 timeout = 30000 connect() // Returns connection result}run không có receiver
Phần tiêu đề “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
Phần tiêu đề “🔗 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
Phần tiêu đề “Use case: Group operations on object”val config = with(Configuration()) { host = "localhost" port = 8080 timeout = 5000 this // Return config}🛠️ apply
Phần tiêu đề “🛠️ 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
Phần tiêu đề “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
Phần tiêu đề “👀 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
Phần tiêu đề “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
Phần tiêu đề “🎯 Chọn Scope Function phù hợp”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]Quy tắc đơn giản
Phần tiêu đề “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
Phần tiêu đề “🛠️ Thực hành”Bài tập 1: Refactor code với scope functions
// Beforefun createUser(): User { val user = User() user.name = "Alice" user.age = 25 println("Created user: $user") return user}
// TODO: Refactor dùng apply và alsoLờ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}")}📱 Trong Android
Phần tiêu đề “📱 Trong Android”// View configuration with applyval button = Button(context).apply { text = "Click Me" setTextColor(Color.WHITE) setBackgroundColor(Color.BLUE) setOnClickListener { handleClick() }}
// Intent with applystartActivity(Intent(this, DetailActivity::class.java).apply { putExtra("ITEM_ID", item.id) putExtra("ITEM_NAME", item.name)})
// Null-safe with letuser?.let { currentUser -> binding.nameText.text = currentUser.name binding.emailText.text = currentUser.email binding.avatarImage.load(currentUser.avatarUrl)}
// Logging with alsoviewModel.loadData() .also { Log.d(TAG, "Data loaded: ${it.size} items") } .also { analytics.trackDataLoad(it.size) }⚠️ Lưu ý quan trọng
Phần tiêu đề “⚠️ Lưu ý quan trọng”✅ Checklist - Tự kiểm tra
Phần tiêu đề “✅ 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