Appearance
Kotlin Lambda 表达式详解 🎯
Android 面试必考 Kotlin Lambda 表达式,包含 Lambda 语法、匿名函数、接收者的 Lambda、Lambda 捕获、性能优化等核心知识点
目录
1. Lambda 语法
1.1 基础语法
Lambda 表达式是匿名函数的简洁表示形式:
kotlin
// 完整语法:{ 参数 -> 函数体 }
val sum = { a: Int, b: Int -> a + b }
// 类型推断(推荐)
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 单个参数可以使用 it(省略参数声明)
val double: (Int) -> Int = { it * 2 }
// 无参数
val greet: () -> String = { "Hello" }
// 无返回值
val printHello: () -> Unit = { println("Hello") }
// 多行 Lambda
val complex = { x: Int, y: Int ->
val sum = x + y
val product = x * y
sum + product // 最后一行是返回值
}1.2 Lambda 的参数
kotlin
// 多个参数
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 带类型声明
val sum2 = { a: Int, b: Int -> a + b }
// 使用 it(单个参数)
val numbers = listOf(1, 2, 3)
numbers.forEach { println(it) }
// 自定义参数名(更清晰)
numbers.forEach { number ->
println("Number: $number")
}
// 多个参数必须命名
val pairs = listOf(1 to "a", 2 to "b")
pairs.forEach { (num, str) ->
println("$num: $str")
}
// 忽略不需要的参数
listOf(1, 2, 3).forEach { _ ->
println("Item")
}1.3 Lambda 的返回值
kotlin
// 隐式返回(最后一行)
val sum: (Int, Int) -> Int = { a, b ->
a + b // 自动返回
}
// 显式返回
val sum2: (Int, Int) -> Int = { a, b ->
return@sum2 a + b
}
// 带标签的返回(用于嵌套 Lambda)
fun nestedExample() {
val list = listOf(1, 2, 3)
list.forEach {
if (it == 2) {
return@forEach // 只返回当前 Lambda
}
println(it)
}
println("Done") // 会继续执行
}
// 从外部函数返回(需要 inline)
inline fun <T> List<T>.findAndReturn(predicate: (T) -> Boolean): T? {
for (element in this) {
if (predicate(element)) {
return element // 非局部返回
}
}
return null
}1.4 Lambda 作为参数
kotlin
// 尾随 Lambda(最后一个参数是函数)
fun <T> List<T>.customMap(transform: (T) -> Int): List<Int> {
return this.map(transform)
}
// 调用 - Lambda 放在括号外
val numbers = listOf(1, 2, 3)
val result = numbers.customMap {
it * 2
}
// 只有 Lambda 参数时,括号可以省略
fun runBlock(block: () -> Unit) {
block()
}
// 调用
runBlock {
println("Hello")
}
// 多个参数时
fun <T> List<T>.process(
prefix: String,
transform: (T) -> String
): List<String> {
return this.map { "$prefix${transform(it)}" }
}
// 调用
val result = numbers.process("Number: ") {
it.toString()
}1.5 Lambda 的类型推断
kotlin
// 上下文类型推断
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 作为参数时推断
fun operate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
operate(3, 4) { a, b -> a + b } // 推断为 (Int, Int) -> Int
// 返回值推断
fun getOperation(): (Int, Int) -> Int {
return { a, b -> a + b } // 推断返回类型
}
// 属性推断
class Calculator {
var operation: (Int, Int) -> Int = { a, b -> a + b }
}1.6 Lambda 的实际应用
kotlin
// 1. 集合操作
val numbers = listOf(1, 2, 3, 4, 5)
numbers.filter { it % 2 == 0 } // [2, 4]
numbers.map { it * 2 } // [2, 4, 6, 8, 10]
numbers.reduce { acc, num -> acc + num } // 15
// 2. 回调函数
class Button {
var onClick: (() -> Unit)? = null
fun click() {
onClick?.invoke()
}
}
val button = Button()
button.onClick = {
println("Button clicked!")
}
// 3. 协程
lifecycleScope.launch {
val result = withContext(Dispatchers.IO) {
// Lambda 中的代码在 IO 线程执行
api.loadData()
}
// 回到主线程
updateUI(result)
}
// 4. 作用域函数
val person = Person().apply {
name = "张三"
age = 25
}
person.let {
println("Name: ${it.name}")
}
person.run {
println("Age: $age")
}2. Lambda 与匿名函数
2.1 Lambda 表达式
kotlin
// Lambda 表达式
val sum = { a: Int, b: Int -> a + b }
// 简洁,但不能指定返回类型
// 返回值由最后一行推断
// 不能从 Lambda 中非局部返回(除非 inline)
fun example() {
listOf(1, 2, 3).forEach {
if (it == 2) {
// return // ❌ 错误:不能从 Lambda 返回
return@forEach // ✅ 正确:从 Lambda 返回
}
}
}2.2 匿名函数
kotlin
// 匿名函数语法
val sum = fun(a: Int, b: Int): Int {
return a + b
}
// 可以指定返回类型
val divide = fun(a: Int, b: Int): Double {
return a.toDouble() / b
}
// 匿名函数可以非局部返回
fun example() {
listOf(1, 2, 3).forEach(fun(value) {
if (value == 2) {
return // ✅ 正确:从匿名函数返回,不是从 example 返回
}
println(value)
})
}
// 带接收者的匿名函数
val block: StringBuilder.() -> Unit = fun() {
this.append("Hello") // this 是 StringBuilder
append(" World") // this 可以省略
}2.3 Lambda vs 匿名函数对比
kotlin
// Lambda 表达式
val lambda = { x: Int -> x * 2 }
// 匿名函数
val anonymous = fun(x: Int): Int { return x * 2 }
// 对比:
// 1. Lambda 更简洁,匿名函数更明确
// 2. Lambda 返回类型由推断,匿名函数可以显式指定
// 3. Lambda 在 inline 函数中可以非局部返回
// 4. 匿名函数的 return 只从匿名函数本身返回
// 使用场景:
// - 优先使用 Lambda(简洁)
// - 需要显式返回类型时使用匿名函数
// - 需要明确 return 行为时使用匿名函数2.4 带接收者的函数类型
kotlin
// Lambda 形式
val block1: StringBuilder.() -> Unit = {
append("Hello") // this 是 StringBuilder
}
// 匿名函数形式
val block2: StringBuilder.() -> Unit = fun() {
this.append("Hello")
}
// 使用
val sb = StringBuilder()
sb.block1()
sb.block2()
// 实际应用:DSL 构建器
class Dialog {
var title: String = ""
var message: String = ""
}
fun dialog(configure: Dialog.() -> Unit): Dialog {
return Dialog().apply(configure)
}
// 使用
dialog {
title = "提示"
message = "确定吗?"
}2.5 函数引用
kotlin
// 函数引用是 Lambda 的另一种形式
fun add(a: Int, b: Int): Int = a + b
val sum = ::add // 函数引用
// 调用
val result = sum(3, 4) // 7
// 方法引用
class Calculator {
fun add(a: Int, b: Int): Int = a + b
}
val calc = Calculator()
val sum2 = calc::add
// 构造函数引用
val createList = ::ArrayList
val list = createList<Int>()
// 属性引用
class User(val name: String)
val user = User("张三")
val getName = User::name
val nameValue = getName.get(user) // "张三"3. 接收者的 Lambda
3.1 带接收者的函数类型
kotlin
// 语法:接收者类型。(参数) -> 返回类型
val block: StringBuilder.() -> Unit = {
append("Hello") // this 是 StringBuilder
append(" ")
append("World")
}
// 使用
val sb = StringBuilder()
sb.block() // 在 StringBuilder 的上下文中执行
println(sb.toString()) // "Hello World"
// 显式使用 this
val block2: StringBuilder.() -> Unit = {
this.append("Hello") // 显式 this
}3.2 标准库中的接收者 Lambda
kotlin
// let - 接收者是 it
val result = "Kotlin".let {
it.uppercase() // it 是 String
}
// run - 接收者是 this
val result2 = "Kotlin".run {
this.uppercase() // this 是 String
length // 返回最后一行
}
// with - 接收者是 this(不是扩展函数)
val result3 = with(StringBuilder()) {
append("Hello")
append(" World")
toString()
}
// apply - 接收者是 this,返回 this
val sb = StringBuilder().apply {
append("Hello")
append(" World")
} // sb 是 StringBuilder
// also - 接收者是 it,返回 this
val sb2 = StringBuilder().also {
it.append("Hello")
} // sb2 是 StringBuilder3.3 创建 DSL
kotlin
// HTML 构建器 DSL
interface Element {
fun render(): String
}
class Tag(val name: String, val children: MutableList<Element> = mutableListOf()) : Element {
override fun render(): String {
return "<$name>${children.joinToString("") { it.render() }}</$name>"
}
}
class Text(val text: String) : Element {
override fun render(): String = text
}
fun tag(name: String, init: Tag.() -> Unit = {}): Tag {
val tag = Tag(name)
tag.init()
return tag
}
fun text(text: String): Text = Text(text)
fun Tag.child(element: Element) {
children.add(element)
}
// 使用
val html = tag("html") {
child(tag("body") {
child(tag("h1") {
child(text("Hello DSL"))
})
child(tag("p") {
child(text("This is a DSL example"))
})
})
}
println(html.render())
// <html><body><h1>Hello DSL</h1><p>This is a DSL example</p></body></html>3.4 类型安全的构建器
kotlin
// 配置 DSL
class DatabaseConfig {
var host: String = "localhost"
var port: Int = 5432
var username: String = ""
var password: String = ""
var database: String = ""
fun validate() {
require(username.isNotEmpty()) { "Username is required" }
require(password.isNotEmpty()) { "Password is required" }
require(database.isNotEmpty()) { "Database is required" }
}
}
fun database(init: DatabaseConfig.() -> Unit): DatabaseConfig {
val config = DatabaseConfig()
config.init()
config.validate()
return config
}
// 使用
val dbConfig = database {
host = "192.168.1.100"
port = 5432
username = "admin"
password = "secret"
database = "mydb"
}
// 嵌套 DSL
class Server {
var host: String = ""
var port: Int = 0
val endpoints = mutableListOf<String>()
fun endpoint(path: String, init: EndpointConfig.() -> Unit) {
val config = EndpointConfig(path)
config.init()
endpoints.add(config.path)
}
}
class EndpointConfig(val path: String) {
var method: String = "GET"
var timeout: Long = 5000
}
fun server(init: Server.() -> Unit): Server {
val server = Server()
server.init()
return server
}
// 使用
val serverConfig = server {
host = "localhost"
port = 8080
endpoint("/api/users") {
method = "GET"
timeout = 3000
}
endpoint("/api/posts") {
method = "POST"
}
}3.5 作用域函数对比
kotlin
val person = Person("张三", 25)
// let - 对象为 it,返回 Lambda 结果
val nameLength = person.let {
it.name.length // 返回 Int
}
// run - 对象为 this,返回 Lambda 结果
val nameLength2 = person.run {
name.length // 返回 Int
}
// with - 对象为 this,返回 Lambda 结果(不是扩展函数)
val nameLength3 = with(person) {
name.length // 返回 Int
}
// apply - 对象为 this,返回对象本身
val person2 = Person("李四", 30).apply {
age = 31 // 修改属性
} // 返回 Person
// also - 对象为 it,返回对象本身
val person3 = Person("王五", 35).also {
println("Created: ${it.name}") // 副作用
} // 返回 Person4. Lambda 捕获
4.1 捕获外部变量
kotlin
// Lambda 可以捕获外部变量
fun createCounter(): () -> Int {
var count = 0 // 被捕获的变量
return {
count++
count
}
}
// 使用
val counter = createCounter()
println(counter()) // 1
println(counter()) // 2
println(counter()) // 3
// 捕获的变量是闭包的一部分
// 即使外部函数返回,变量仍然存在4.2 捕获 this
kotlin
// 捕获外部类的 this
class Outer {
private val value = "Outer"
fun getPrinter(): () -> Unit {
return {
println(value) // 捕获 Outer 的 value
}
}
}
// 内层类的 this 捕获
class Outer2 {
val value = "Outer"
inner class Inner {
val value = "Inner"
fun print() {
val block: () -> Unit = {
println(value) // Inner.value(最近的 this)
println(this@Inner.value) // 明确指定 Inner 的 this
println(this@Outer2.value) // 明确指定 Outer2 的 this
}
block()
}
}
}4.3 捕获可变变量
kotlin
// 捕获的可变变量必须是 effectively final(Java 8+)
// Kotlin 中可以直接捕获 var
var count = 0
val increment = {
count++ // 可以修改捕获的 var
}
increment()
println(count) // 1
// 注意:多个 Lambda 捕获同一个 var
var shared = 0
val inc = { shared++ }
val dec = { shared-- }
inc()
inc()
dec()
println(shared) // 14.4 捕获的性能考虑
kotlin
// 捕获变量会创建闭包对象
// 每次捕获都会增加内存开销
// ❌ 避免:在循环中创建捕获 Lambda
fun badExample() {
val results = mutableListOf<() -> Int>()
for (i in 1..10) {
results.add { i } // 每个 Lambda 都捕获 i
}
}
// ✅ 推荐:避免不必要的捕获
fun goodExample() {
val results = mutableListOf<Int>()
for (i in 1..10) {
results.add(i) // 直接存储值
}
}
// 捕获 this 的开销
class MyClass {
private val data = LargeObject()
fun getPrinter(): () -> Unit {
return {
println(data) // 捕获 this,持有 data 引用
}
}
}
// 可能导致内存泄漏
// 如果 Lambda 的生命周期比 MyClass 长4.5 捕获与内存泄漏
kotlin
// Android 中的内存泄漏示例
class MyActivity : AppCompatActivity() {
private var callback: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ❌ 错误:Lambda 捕获 this(Activity)
callback = {
// 使用 Activity 的成员
findViewById<View>(R.id.view)
}
// 如果 callback 的生命周期比 Activity 长
// 会导致 Activity 无法被 GC
}
override fun onDestroy() {
super.onDestroy()
callback = null // 释放引用
}
}
// ✅ 正确做法
class MyActivity2 : AppCompatActivity() {
private var callback: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使用 WeakReference
val weakRef = WeakReference(this)
callback = {
weakRef.get()?.findViewById<View>(R.id.view)
}
}
override fun onDestroy() {
super.onDestroy()
callback = null
}
}
// ✅ 使用 Lifecycle 感知
class MyActivity3 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
// 协程自动感知生命周期
// Activity 销毁时自动取消
delay(1000)
// 安全使用 Activity
}
}
}4.6 捕获最佳实践
kotlin
// 1. 最小化捕获
class DataProcessor {
private val config = Config()
// ❌ 捕获整个 this
val process: (String) -> String = { data ->
config.process(data)
}
// ✅ 只捕获需要的
val process2: (String) -> String = { data ->
config.process(data)
}
}
// 2. 避免循环引用
class MyClass {
var callback: (() -> Unit)? = null
fun setup() {
// ❌ 循环引用:this 持有 callback,callback 捕获 this
callback = {
doSomething()
}
}
// ✅ 使用 WeakReference
fun setup2() {
val weakRef = WeakReference(this)
callback = {
weakRef.get()?.doSomething()
}
}
}
// 3. 及时清理
class MyViewModel : ViewModel() {
private var listener: ((String) -> Unit)? = null
fun setListener(listener: (String) -> Unit) {
this.listener = listener
}
override fun onCleared() {
super.onCleared()
listener = null // 清理回调
}
}5. Lambda 性能
5.1 Lambda 的对象创建
kotlin
// Lambda 会创建函数对象
// 每次调用都会创建新对象(除非内联)
// 普通 Lambda
fun example() {
val list = listOf(1, 2, 3)
list.forEach { println(it) }
// 1. 创建 Lambda 对象
// 2. 调用 forEach 方法
// 3. 在循环中调用 Lambda
}
// 内联 Lambda
inline fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) action(element)
}
// 内联后直接展开
for (element in this) {
println(element) // 没有 Lambda 对象创建
}5.2 内联优化
kotlin
// inline 关键字消除 Lambda 开销
inline fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
val result = ArrayList<R>(size)
for (item in this) {
result.add(transform(item)) // 内联展开
}
return result
}
// 使用
val result = listOf(1, 2, 3).map {
it * 2 // 直接展开为 result.add(item * 2)
}
// noinline:禁止特定 Lambda 内联
inline fun test(
inlineParam: () -> Unit,
noinline noInlineParam: () -> Unit
) {
inlineParam() // 内联
executeLater(noInlineParam) // 不内联,可以作为对象传递
}
fun executeLater(action: () -> Unit) {
// 延迟执行
action()
}5.3 装箱开销
kotlin
// 基本类型的 Lambda 参数会装箱
val list = listOf(1, 2, 3) // List<Int>,Int 装箱为 Integer
list.forEach {
println(it) // it 是 Integer(装箱)
}
// 使用原始类型数组避免装箱
val array = intArrayOf(1, 2, 3) // IntArray
array.forEach {
println(it) // it 是 int(原始类型)
}
// 自定义内联函数避免装箱
inline fun IntArray.forEach(action: (Int) -> Unit) {
for (i in this.indices) {
action(this[i]) // 没有装箱
}
}5.4 性能对比
kotlin
// 性能测试
fun performanceTest() {
val list = (1..10000).toList()
// 1. 普通 for 循环(最快)
var sum1 = 0
for (item in list) {
sum1 += item
}
// 2. 内联 forEach(接近 for 循环)
var sum2 = 0
list.forEach {
sum2 += it
}
// 3. 非内联 map + sum(较慢)
val sum3 = list.map { it * 2 }.sum()
// 4. 序列(惰性求值,适合大数据)
val sum4 = list.asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.sum()
}
// 建议:
// - 简单遍历使用 for 循环或内联 forEach
// - 复杂链式操作使用序列(Sequence)
// - 避免在循环中创建对象5.5 序列优化
kotlin
// 序列:惰性求值,避免中间集合
val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// List:立即求值,创建中间集合
val result1 = list
.filter {
println("Filter: $it")
it % 2 == 0
}
.map {
println("Map: $it")
it * 2
}
.take(2)
// 所有元素都经过 filter 和 map,即使只取 2 个
// Sequence:惰性求值,不创建中间集合
val result2 = list.asSequence()
.filter {
println("Filter: $it")
it % 2 == 0
}
.map {
println("Map: $it")
it * 2
}
.take(2)
.toList()
// 只处理需要的元素
// 使用场景:
// - 大数据集使用 Sequence
// - 短链式操作使用 List
// - 需要多次遍历使用 List5.6 性能最佳实践
kotlin
// 1. 使用内联函数
inline fun <T> List<T>.forEach(action: (T) -> Unit)
// 2. 避免在循环中创建 Lambda
// ❌ 不好
for (i in 1..100) {
list.filter { it == i } // 每次创建 Lambda
}
// ✅ 好
val filters = (1..100).map { i ->
list.filter { it == i }
}
// 3. 使用序列处理大数据
largeList.asSequence()
.filter { it > 0 }
.map { it * 2 }
.take(10)
.toList()
// 4. 避免不必要的装箱
val array = intArrayOf(1, 2, 3)
array.forEach { println(it) } // 没有装箱
// 5. 使用合适的集合操作
// ❌ 不好:创建中间集合
val result = list.filter { it > 0 }.map { it * 2 }
// ✅ 好:单次遍历
val result = list.mapNotNull {
if (it > 0) it * 2 else null
}6. 面试考点汇总
6.1 基础问题
Q1: Lambda 表达式的语法是什么?
kotlin
// 答案要点:
// 1. { 参数 -> 函数体 }
// 2. 单个参数可以用 it
// 3. 类型可以推断
// 4. 最后一行是返回值
// 完整语法
val sum = { a: Int, b: Int -> a + b }
// 类型推断
val sum: (Int, Int) -> Int = { a, b -> a + b }
// 单个参数
val double: (Int) -> Int = { it * 2 }
// 多行 Lambda
val complex = { x: Int ->
val result = x * 2
result + 1 // 返回值
}Q2: Lambda 和匿名函数的区别?
kotlin
// 答案要点:
// 1. Lambda 更简洁,匿名函数更明确
// 2. Lambda 返回类型由推断,匿名函数可以显式指定
// 3. Lambda 在 inline 函数中可以非局部返回
// 4. 匿名函数的 return 只从匿名函数本身返回
// Lambda
val lambda = { x: Int -> x * 2 }
// 匿名函数
val anonymous = fun(x: Int): Int { return x * 2 }Q3: 什么是尾随 Lambda?
kotlin
// 答案要点:
// 1. 最后一个参数是函数时可以放在括号外
// 2. 如果只有 Lambda 参数,括号可以省略
// 3. 提高代码可读性
// 尾随 Lambda
list.map { it * 2 }
// 只有 Lambda 参数
run {
println("Hello")
}
// 多个参数
list.fold(0) { acc, num ->
acc + num
}6.2 进阶问题
Q4: Lambda 如何捕获外部变量?
kotlin
// 答案要点:
// 1. Lambda 可以捕获外部作用域的变量
// 2. 捕获的变量形成闭包
// 3. 可以捕获 var 并修改
// 4. 注意内存泄漏风险
// 捕获示例
fun createCounter(): () -> Int {
var count = 0
return {
count++
count
}
}
val counter = createCounter()
println(counter()) // 1, 2, 3...Q5: 带接收者的 Lambda 如何使用?
kotlin
// 答案要点:
// 1. 函数类型:Receiver.(Params) -> Return
// 2. Lambda 内 this 指向接收者
// 3. 用于 DSL 和作用域函数
// 4. 标准库:let、run、with、apply、also
// 定义
val block: StringBuilder.() -> Unit = {
append("Hello") // this 是 StringBuilder
}
// 使用
val sb = StringBuilder()
sb.block()
// 作用域函数
person.let { it.name }
person.run { name }Q6: inline 关键字的作用?
kotlin
// 答案要点:
// 1. 将 Lambda 代码内联到调用处
// 2. 避免 Lambda 对象创建开销
// 3. 支持非局部返回
// 4. 需要 reified 时使用
inline fun <T> List<T>.forEach(action: (T) -> Unit) {
for (element in this) action(element)
}
// 内联后直接展开
for (element in this) {
println(element)
}6.3 原理问题
Q7: Lambda 的性能开销?
kotlin
// 答案要点:
// 1. Lambda 会创建函数对象
// 2. 有分配和 GC 开销
// 3. 使用 inline 可以消除开销
// 4. 基本类型参数注意装箱
// 普通 Lambda
list.forEach { println(it) }
// 1. 创建 Lambda 对象
// 2. 调用 forEach
// 3. 调用 Lambda
// 内联 Lambda
inline fun <T> List<T>.forEach(action: (T) -> Unit)
// 直接展开,无对象创建Q8: 闭包的实现原理?
kotlin
// 答案要点:
// 1. Lambda 捕获外部变量形成闭包
// 2. 捕获的变量存储在 Lambda 对象中
// 3. 即使外部函数返回,变量仍然存在
// 4. 可变变量需要特殊处理
// 闭包示例
fun createCounter(): () -> Int {
var count = 0 // 被捕获
return { count++ }
}
// count 存储在 Lambda 对象中
// 即使 createCounter 返回,count 仍然存在6.4 实战问题
Q9: 如何避免 Lambda 导致的内存泄漏?
kotlin
// 答案要点:
// 1. 注意 Lambda 捕获 this
// 2. 使用 WeakReference
// 3. 及时清理回调引用
// 4. 使用 Lifecycle 感知组件
// Android 示例
class MyActivity : AppCompatActivity() {
private var callback: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 使用 WeakReference
val weakRef = WeakReference(this)
callback = {
weakRef.get()?.findViewById<View>(R.id.view)
}
}
override fun onDestroy() {
super.onDestroy()
callback = null // 清理
}
}Q10: 如何使用 Lambda 创建 DSL?
kotlin
// 答案要点:
// 1. 使用带接收者的 Lambda
// 2. 使用 apply/scope 函数
// 3. 提供清晰的配置 API
// 4. 返回构建的对象
// DSL 示例
class Dialog {
var title: String = ""
var message: String = ""
}
fun dialog(configure: Dialog.() -> Unit): Dialog {
return Dialog().apply(configure)
}
// 使用
dialog {
title = "提示"
message = "确定吗?"
}Q11: 标准库中有哪些作用域函数?
kotlin
// 答案要点:
// 1. let - 对象为 it,返回 Lambda 结果
// 2. run - 对象为 this,返回 Lambda 结果
// 3. with - 对象为 this,返回 Lambda 结果(非扩展)
// 4. apply - 对象为 this,返回对象本身
// 5. also - 对象为 it,返回对象本身
val person = Person("张三", 25)
person.let { it.name } // it 是 Person
person.run { name } // this 是 Person
with(person) { name } // this 是 Person
person.apply { age = 26 } // 返回 Person
person.also { println(it) } // 返回 Person最佳实践总结
✅ 推荐做法
kotlin
// 1. 使用简洁的 Lambda 语法
list.map { it * 2 }
// 2. 使用尾随 Lambda
list.fold(0) { acc, num ->
acc + num
}
// 3. 使用内联函数
inline fun <T> List<T>.forEach(action: (T) -> Unit)
// 4. 清晰命名 Lambda 参数
list.map { number -> number * 2 }
// 5. 使用作用域函数
person.let { println(it.name) }❌ 避免做法
kotlin
// 1. 避免过长的 Lambda
list.map {
// 几十行代码
}
// 2. 避免嵌套过深
list.map { x ->
list2.map { y ->
list3.map { z ->
// ...
}
}
}
// 3. 避免内存泄漏
// Lambda 捕获 this 时要注意生命周期
// 4. 避免不必要的装箱
// 使用原始类型数组参考资料
最后更新:2026-04-14