📍 Local Functions
🎯 Mục tiêu: Hiểu Local Functions - hàm lồng bên trong hàm khác, giúp tổ chức code tốt hơn và tận dụng closure.
💡 Local Functions là gì?
Phần tiêu đề “💡 Local Functions là gì?”Local function là hàm được định nghĩa bên trong hàm khác. Chúng chỉ visible trong scope của outer function.
fun outerFunction() { // Local function - chỉ visible trong outerFunction fun innerFunction() { println("I'm a local function!") }
innerFunction() // Gọi local function}
fun main() { outerFunction() // innerFunction() // ❌ Lỗi! Không thể gọi từ bên ngoài}📝 Closure - Truy cập biến bên ngoài
Phần tiêu đề “📝 Closure - Truy cập biến bên ngoài”Local functions có thể truy cập và modify biến của outer function (closure):
fun calculateTotal(prices: List<Double>, taxRate: Double): Double { var total = 0.0 var taxAmount = 0.0
// Local function access biến bên ngoài fun addPrice(price: Double) { val tax = price * taxRate total += price taxAmount += tax }
for (price in prices) { addPrice(price) }
println("Subtotal: $total, Tax: $taxAmount") return total + taxAmount}
fun main() { val prices = listOf(100.0, 200.0, 50.0) val total = calculateTotal(prices, 0.1) println("Total: $total") // Subtotal: 350.0, Tax: 35.0 // Total: 385.0}🎯 Use Case 1: Validation
Phần tiêu đề “🎯 Use Case 1: Validation”Tránh lặp code validation:
// ❌ Không tốt: Code lặpfun saveUser(name: String, email: String, phone: String) { if (name.isBlank()) throw IllegalArgumentException("Name cannot be blank") if (email.isBlank()) throw IllegalArgumentException("Email cannot be blank") if (phone.isBlank()) throw IllegalArgumentException("Phone cannot be blank") // Save...}
// ✅ Tốt hơn: Local functionfun saveUser(name: String, email: String, phone: String) { fun validate(value: String, fieldName: String) { if (value.isBlank()) { throw IllegalArgumentException("$fieldName cannot be blank") } }
validate(name, "Name") validate(email, "Email") validate(phone, "Phone")
// Validation passed, save user... println("Saving user: $name, $email, $phone")}Validation nâng cao
Phần tiêu đề “Validation nâng cao”data class User(val name: String, val email: String, val age: Int)
fun registerUser(user: User) { fun validateField(value: Any?, fieldName: String, validator: (Any?) -> Boolean, message: String) { if (!validator(value)) { throw IllegalArgumentException("$fieldName: $message") } }
validateField(user.name, "Name", { it is String && it.isNotBlank() }, "cannot be blank") validateField(user.email, "Email", { it is String && it.contains("@") }, "must be valid email") validateField(user.age, "Age", { it is Int && it >= 18 }, "must be at least 18")
println("User registered: ${user.name}")}
fun main() { // registerUser(User("Bob", "invalid", 16)) // ❌ Age: must be at least 18}🔄 Use Case 2: Recursive Helper
Phần tiêu đề “🔄 Use Case 2: Recursive Helper”Local function thường được dùng cho recursive helper:
fun findPathsInTree(root: TreeNode?): List<List<Int>> { val allPaths = mutableListOf<List<Int>>()
// Recursive local function fun dfs(node: TreeNode?, currentPath: MutableList<Int>) { if (node == null) return
currentPath.add(node.value)
if (node.left == null && node.right == null) { // Leaf node - save path allPaths.add(currentPath.toList()) } else { dfs(node.left, currentPath) dfs(node.right, currentPath) }
currentPath.removeAt(currentPath.lastIndex) // Backtrack }
dfs(root, mutableListOf()) return allPaths}Ví dụ đơn giản: Fibonacci
Phần tiêu đề “Ví dụ đơn giản: Fibonacci”fun fibonacci(n: Int): Long { val cache = mutableMapOf<Int, Long>()
fun fib(k: Int): Long { if (k <= 1) return k.toLong()
return cache.getOrPut(k) { fib(k - 1) + fib(k - 2) } }
return fib(n)}
fun main() { println(fibonacci(50)) // 12586269025 (fast with memoization)}📋 Use Case 3: Tổ chức code phức tạp
Phần tiêu đề “📋 Use Case 3: Tổ chức code phức tạp”Chia nhỏ logic phức tạp mà không expose helper functions:
fun processOrder(order: Order): OrderResult { // Local functions để tổ chức code fun validateOrder(): Boolean { return order.items.isNotEmpty() && order.total > 0 }
fun calculateDiscount(): Double { return when { order.total > 1000 -> order.total * 0.1 order.total > 500 -> order.total * 0.05 else -> 0.0 } }
fun applyTax(amount: Double): Double { return amount * 1.1 // 10% tax }
fun createReceipt(finalAmount: Double): String { return """ Order #${order.id} Items: ${order.items.size} Subtotal: $${order.total} Discount: $${calculateDiscount()} Final (with tax): $${"%.2f".format(finalAmount)} """.trimIndent() }
// Main logic if (!validateOrder()) { return OrderResult.Error("Invalid order") }
val discount = calculateDiscount() val afterDiscount = order.total - discount val finalAmount = applyTax(afterDiscount) val receipt = createReceipt(finalAmount)
return OrderResult.Success(finalAmount, receipt)}🔧 Local Extension Functions
Phần tiêu đề “🔧 Local Extension Functions”Bạn cũng có thể tạo local extension functions:
fun processText(text: String): String { // Local extension function fun String.normalize(): String { return this.trim().lowercase().replace("\\s+".toRegex(), " ") }
fun String.titleCase(): String { return split(" ").joinToString(" ") { word -> word.replaceFirstChar { it.uppercase() } } }
return text.normalize().titleCase()}
fun main() { val result = processText(" HELLO WORLD ") println(result) // Hello World}🛠️ Thực hành
Phần tiêu đề “🛠️ Thực hành”Bài tập: Refactor với local functions
// ❌ Code lặpfun printUserReport(users: List<User>) { println("=".repeat(50)) println("USER REPORT") println("=".repeat(50))
for (user in users) { println("-".repeat(30)) println("Name: ${user.name}") println("Email: ${user.email}") println("-".repeat(30)) }
println("=".repeat(50)) println("Total: ${users.size} users") println("=".repeat(50))}
// TODO: Refactor dùng local functionsLời giải:
data class User(val name: String, val email: String)
fun printUserReport(users: List<User>) { fun separator(char: Char = '-', length: Int = 50) { println(char.toString().repeat(length)) }
fun header(title: String) { separator('=') println(title) separator('=') }
fun userSection(user: User) { separator() println("Name: ${user.name}") println("Email: ${user.email}") }
fun footer(count: Int) { separator() separator('=') println("Total: $count users") separator('=') }
header("USER REPORT") users.forEach { userSection(it) } footer(users.size)}
fun main() { val users = listOf( ) printUserReport(users)}📱 Trong Android
Phần tiêu đề “📱 Trong Android”class UserViewModel : ViewModel() {
fun loadAndDisplayUser(userId: String) { // Local validation fun isValidId(id: String): Boolean { return id.isNotBlank() && id.length >= 5 }
// Local error handler fun handleError(error: Throwable) { _error.value = when (error) { is NetworkException -> "Network error" is NotFoundException -> "User not found" else -> "Unknown error" } }
// Local success handler fun handleSuccess(user: User) { _user.value = user _loading.value = false }
if (!isValidId(userId)) { _error.value = "Invalid user ID" return }
viewModelScope.launch { _loading.value = true try { val user = repository.getUser(userId) handleSuccess(user) } catch (e: Exception) { handleError(e) } } }}⚠️ 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ể:
- Tạo local functions bên trong functions khác
- Hiểu closure - truy cập và modify biến bên ngoài
- Sử dụng local functions cho validation
- Sử dụng local functions cho recursive helpers
- Tổ chức code phức tạp với local functions
- Tạo local extension functions
Tiếp theo: Lambda Expressions