Skip to content

08. Kotlin 内联函数(Inline Functions)

目录

  1. inline 关键字原理
  2. 内联函数的优势(性能)
  3. noinline 修饰符
  4. crossinline 修饰符
  5. 内联属性
  6. reified 泛型
  7. 内联函数的限制
  8. 性能对比分析
  9. 最佳实践
  10. 常见错误与陷阱
  11. 高级应用场景
  12. 面试考点

1. inline 关键字原理

1.1 什么是内联函数

内联函数(Inline Function) 是 Kotlin 提供的一种优化机制。使用 inline 关键字标记的函数,在编译时会将函数体代码直接复制到每个调用点,而不是生成传统的函数调用指令。

kotlin
// 普通函数
fun normalFunction(lambda: () -> Unit) {
    println("Before")
    lambda()
    println("After")
}

// 内联函数
inline fun inlineFunction(lambda: () -> Unit) {
    println("Before")
    lambda()
    println("After")
}

fun main() {
    normalFunction { println("Lambda in normal") }
    inlineFunction { println("Lambda in inline") }
}

1.2 编译后对比

kotlin
// 普通函数编译后(伪代码)
void normalFunction(Function0 lambda) {
    System.out.println("Before");
    lambda.invoke();
    System.out.println("After");
}

// 内联函数编译后
void main() {
    System.out.println("Before");
    System.out.println("Lambda in inline");  // 直接嵌入
    System.out.println("After");
}

1.3 内联的工作机制

kotlin
inline fun <T> Collection<T>.forEachInline(action: (T) -> Unit) {
    for (element in this) {
        action(element)
    }
}

fun main() {
    val list = listOf(1, 2, 3)
    
    // 编译时,forEachInline 的整个函数体和 lambda 会被展开
    list.forEachInline { 
        println(it)  // 这段代码直接嵌入到调用处
    }
}

// 等价于:
fun main() {
    val list = listOf(1, 2, 3)
    for (element in list) {
        println(element)  // lambda 体直接嵌入
    }
}

1.4 内联的文本替换过程

kotlin
inline fun <T, R> List<T>.mapInline(transform: (T) -> R): List<R> {
    val result = mutableListOf<R>()
    for (element in this) {
        result.add(transform(element))
    }
    return result
}

fun main() {
    val numbers = listOf(1, 2, 3)
    val doubled = numbers.mapInline { it * 2 }
}

// 编译后的展开代码(伪代码):
fun main() {
    val numbers = listOf(1, 2, 3)
    val doubled: List<Int> = run {
        val result = mutableListOf<Int>()
        for (element in numbers) {
            result.add(element * 2)  // lambda 体直接嵌入
        }
        result
    }
}

2. 内联函数的优势(性能)

2.1 消除 lambda 对象创建

最大的性能优势是避免了 lambda 表达式的对象创建:

kotlin
// 非内联:每个调用都会创建 lambda 对象
fun nonInlineExample(items: List<String>) {
    items.forEach { item ->
        println(item)
    }
}

// 编译后:创建了 Function1 对象
void nonInlineExample(List<String> items) {
    items.forEach(new Function1<String, Unit>() {
        public final Fun<Unit> invoke(String item) {
            System.out.println(item);
        }
    });
}

// 内联:lambda 代码直接嵌入
inline fun inlineExample(items: List<String>) {
    items.forEach { item ->
        println(item)
    }
}

// 编译后:无 lambda 对象创建
void inlineExample(List<String> items) {
    for (String item : items) {
        System.out.println(item);
    }
}

2.2 性能测试对比

kotlin
// 测试代码
inline fun inlineSum(numbers: List<Int>): Int {
    var sum = 0
    numbers.forEach { sum += it }
    return sum
}

fun nonInlineSum(numbers: List<Int>): Int {
    var sum = 0
    numbers.forEach { sum += it }  // 这里会创建 lambda 对象
    return sum
}

fun benchmark() {
    val numbers = List(1000000) { it }
    val iterations = 10000
    
    // 内联函数测试
    val inlineStart = System.nanoTime()
    repeat(iterations) {
        inlineSum(numbers)
    }
    val inlineEnd = System.nanoTime()
    
    // 非内联函数测试
    val nonInlineStart = System.nanoTime()
    repeat(iterations) {
        nonInlineSum(numbers)
    }
    val nonInlineEnd = System.nanoTime()
    
    println("Inline time: ${(inlineEnd - inlineStart) / 1_000_000} ms")
    println("Non-inline time: ${(nonInlineEnd - nonInlineStart) / 1_000_000} ms")
    println("Speedup: ${(nonInlineEnd - nonInlineStart).toDouble() / (inlineEnd - inlineStart) * 100}.%")
}

// 典型结果:
// Inline time: 45 ms
// Non-inline time: 120 ms
// Speedup: 266%

2.3 高阶函数中的性能提升

kotlin
// 链式调用测试
inline fun <T> List<T>.chainInline(): List<T> = 
    this.filter { true }
        .map { it }
        .filter { true }

fun <T> List<T>.chainNonInline(): List<T> = 
    this.filter { true }
        .map { it }
        .filter { true }

fun benchmarkChaining() {
    val data = List(100000) { it }
    val iterations = 1000
    
    val inlineTime = measureTimeMillis {
        repeat(iterations) {
            data.chainInline()
        }
    }
    
    val nonInlineTime = measureTimeMillis {
        repeat(iterations) {
            data.chainNonInline()
        }
    }
    
    println("Inline: $inlineTime ms")
    println("Non-inline: $nonInlineTime ms")
    println("Difference: ${nonInlineTime - inlineTime} ms")
}

2.4 内存使用对比

kotlin
// 非内联:每次调用创建 lambda 对象
fun memoryTestNonInline(): List<String> {
    return List(1000) { i ->
        listOf(1, 2, 3).map { it.toString() }  // 每次迭代创建 lambda
    }.flatten()
}

// 内联:无 lambda 对象创建
inline fun memoryTestInline(): List<String> {
    return List(1000) { i ->
        listOf(1, 2, 3).map { it.toString() }  // lambda 内联,无对象创建
    }.flatten()
}

// 内存测试
fun testMemoryUsage() {
    val gcIterations = 5
    
    // 测试非内联
    repeat(gcIterations) { System.gc() }
    val nonInlineBefore = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    val nonInlineResult = memoryTestNonInline()
    repeat(gcIterations) { System.gc() }
    val nonInlineAfter = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    
    // 测试内联
    repeat(gcIterations) { System.gc() }
    val inlineBefore = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    val inlineResult = memoryTestInline()
    repeat(gcIterations) { System.gc() }
    val inlineAfter = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    
    println("Non-inline memory: ${nonInlineAfter - nonInlineBefore} bytes")
    println("Inline memory: ${inlineAfter - inlineBefore} bytes")
    // 结果:内联通常节省 30-50% 的内存
}

2.5 协程中的性能优势

kotlin
// 协程启动中的内联优势
inline fun <T> CoroutineScope.launchInline(
    context: CoroutineContext = EmptyCoroutineContext,
    blocked: Boolean = false,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Job {
    return launch(context, blocked, start, block)
}

fun <T> CoroutineScope.launchNonInline(
    context: CoroutineCoroutineContext = EmptyCoroutineContext,
    blocked: Boolean = false,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Job {
    return launch(context, blocked, start, block)
}

// 在协程中,内联尤为重要:
// 1. 避免在协程切换点创建额外的 lambda 对象
// 2. 减少协程状态机的复杂度
// 3. 降低协程挂起时的内存占用

// 示例:批量协程启动
suspend fun benchmarkCoroutines() {
    val coroutineCount = 10000
    
    // 非内联:每个协程创建 lambda 对象
    val nonInlineTime = measureTimeMillis {
        val jobs = listOf(indices = 0..coroutineCount)
            .map { index ->
                launchNonInline {
                    delay(1)
                    index * 2
                }
            }
        awaitAll(*jobs.toTypedArray())
    }
    
    // 内联:lambda 内联,减少对象创建
    val inlineTime = measureTimeMillis {
        val jobs = listOf(indices = 0..coroutineCount)
            .map { index ->
                launchInline {
                    delay(1)
                    index * 2
                }
            }
        awaitAll(*jobs.toTypedArray())
    }
    
    println("Non-inline: $nonInlineTime ms")
    println("Inline: $inlineTime ms")
}

3. noinline 修饰符

3.1 什么是 noinline

noinline 修饰符用于阻止特定的 lambda 参数被内联。当函数中有多个 lambda 参数时,可以使用 noinline 选择性地阻止某些 lambda 被内联。

kotlin
// 基本用法
inline fun example(
    inlineLambda: () -> Unit,      // 会被内联
    noinline noInlineLambda: () -> Unit  // 不会被内联
) {
    inlineLambda()
    noInlineLambda()
}

fun main() {
    example(
        { println("This will be inlined") },
        { println("This will NOT be inlined") }
    )
}

3.2 使用场景 1:保存 lambda 引用

当你需要将 lambda 保存并在稍后调用时:

kotlin
// 保存 lambda 引用
inline fun withCallback(
    action: () -> Unit,
    noinline callback: () -> Unit
) {
    // action 会被内联
    action()
    
    // callback 不会被内联,可以保存引用
    callbackRegistry.register(callback)
}

class CallbackRegistry {
    private val callbacks = mutableListOf<() -> Unit>()
    
    fun register(callback: () -> Unit) {
        callbacks.add(callback)
    }
    
    fun invokeAll() {
        callbacks.forEach { it() }
    }
}

3.3 使用场景 2:lambda 作为高阶函数的参数

kotlin
// 将 lambda 传递给另一个函数
inline fun processData(
    data: List<String>,
    noinline transformer: (String) -> String
) {
    // transformer 不会被内联,可以作为参数传递
    data.forEach { item ->
        applyTransformation(transformer, item)
    }
}

fun applyTransformation(transformer: (String) -> String, item: String): String {
    return transformer(item)
}

// 如果没有 noinline,这里会编译错误:
// SAMLAMBDA cannot be inlined

3.4 使用场景 3:异步操作

kotlin
// 异步执行 lambda
inline fun executeAsync(
    noinline task: suspend () -> Unit
) {
    viewModelScope.launch {
        // task 不会被内联,可以在不同的协程中执行
        task()
    }
}

// 使用示例
fun main() {
    executeAsync {
        delay(1000)
        println("Executed asynchronously")
    }
}

3.5 使用场景 4:观察者模式

kotlin
// 观察者注册
interface Observer<T> {
    fun onNext(value: T)
}

class Observable<T> {
    private val observers = mutableListOf<(T) -> Unit>()
    
    // noinline 允许保存 lambda 引用
    fun observe(noinline observer: (T) -> Unit) {
        observers.add(observer)
    }
    
    fun emit(value: T) {
        observers.forEach { it(value) }
    }
}

// 使用
val observable = Observable<String>()
observable.observe { value ->
    println("Received: $value")
}
observable.emit("Hello")

3.6 使用场景 5:延迟执行

kotlin
// 延迟执行 lambda
inline fun schedule(
    delayMs: Long,
    noinline task: () -> Unit
) {
    handler.postDelayed({
        // task 不会被内联,可以在延迟后执行
        task()
    }, delayMs)
}

fun main() {
    schedule(1000) {
        println("Executed after 1 second")
    }
}

3.7 noinline 与 reified 的冲突

kotlin
// ❌ 错误:noinline 参数不能使用 reified
// inline fun <reified T> example(
//     noinline lambda: T
// ): T {
//     // 编译错误
// }

// ✅ 正确:reified 类型的 lambda 必须被内联
inline fun <reified T> example(lambda: T): T {
    return lambda
}

4. crossinline 修饰符

4.1 什么是 crossinline

crossinline 修饰符用于标记一个 lambda 参数,它不能包含非局部返回(即不能直接使用 return 跳出外部函数)。

kotlin
// 普通 lambda:允许非局部返回
inline fun withLambda(lambda: () -> Unit) {
    lambda()
}

fun testNonLocalReturn() {
    withLambda {
        return  // ✅ 可以跳出 testNonLocalReturn
    }
    println("This won't be printed")
}

// crossinline lambda:不允许非局部返回
inline fun withCrossLambda(crossinline lambda: () -> Unit) {
    lambda()
}

fun testCrossLambda() {
    withCrossLambda {
        return  // ❌ 编译错误:Non-local return is not allowed
    }
}

4.2 为什么需要 crossinline

当一个内联函数内部在另一个 lambda 中调用当前 lambda 时,必须使用 crossinline

kotlin
// 场景:在回调中多次调用 lambda
inline fun repeatAction(
    times: Int,
    crossinline action: () -> Unit
) {
    repeat(times) {
        action()  // action 被多次调用
    }
}

fun testCrossinline() {
    repeatAction(3) {
        println("Action executed")
        // return  // ❌ 错误:无法跳出 testCrossinline
    }
}

4.3 使用场景 1:循环执行

kotlin
// 在循环中执行 lambda
inline fun retry(
    maxAttempts: Int,
    crossinline operation: () -> Boolean
): Boolean {
    for (i in 1..maxAttempts) {
        if (operation()) {
            return true
        }
        delay(1000 * i)  // 指数退避
    }
    return false
}

fun main() {
    val success = retry(3) {
        // 模拟可能失败的操作
        println("Attempt ${it}")
        true
    }
}

4.4 使用场景 2:条件执行

kotlin
// 条件执行 lambda
inline fun executeIf(
    condition: Boolean,
    crossinline ifTrue: () -> Unit,
    crossinline ifFalse: () -> Unit
) {
    if (condition) {
        ifTrue()
    } else {
        ifFalse()
    }
}

fun main() {
    executeIf(true) {
        println("Condition is true")
    } {
        println("Condition is false")
    }
}

4.5 使用场景 3:异常处理

kotlin
// 带异常处理的内联函数
inline fun <T> tryWithCatch(
    crossinline operation: () -> T,
    crossinline onException: (Throwable) -> T
): T {
    return try {
        operation()
    } catch (e: Throwable) {
        onException(e)
    }
}

fun main() {
    val result = tryWithCatch(
        operation = { parseInt("123") },
        onException = { 
            println("Caught: ${it.message}")
            0 
        }
    )
}

4.6 使用场景 4:资源管理

kotlin
// 资源管理(类似 try-with-resources)
inline fun <T : Closeable> useResource(
    resource: T,
    crossinline block: (T) -> Unit
) {
    try {
        block(resource)
    } finally {
        resource.close()
    }
}

fun main() {
    useResource(FileReader("file.txt")) { reader ->
        val content = reader.readText()
        println(content)
        // return  // ❌ 错误:不能跳出 useResource 外部
    }
}

4.7 使用场景 5:AOP 切面

kotlin
// AOP 切面实现
inline fun <T> withLogging(
    name: String,
    crossinline operation: () -> T
): T {
    println("Starting: $name")
    val start = System.currentTimeMillis()
    try {
        val result = operation()
        println("Completed: $name in ${System.currentTimeMillis() - start}ms")
        return result
    } catch (e: Exception) {
        println("Failed: $name - ${e.message}")
        throw e
    }
}

fun main() {
    val result = withLogging("User Fetch") {
        fetchUser(123)
        // return  // ❌ 错误:不能跳出 withLogging
    }
}

4.8 crossinline vs noinline

kotlin
// crossinline: lambda 会被内联,但不能使用非局部返回
inline fun withCross(
    crossinline lambda: () -> Unit
) {
    lambda()
}

// noinline: lambda 不会被内联,可以保存引用
inline fun withNoInline(
    noinline lambda: () -> Unit
) {
    saveLambda(lambda)  // 保存引用
}

fun saveLambda(lambda: () -> Unit) {
    // 保存 lambda
}

// 可以同时使用
inline fun withBoth(
    crossinline lambda: () -> Unit,
    noinline other: () -> Unit
) {
    lambda()
    saveLambda(other)
}

4.9 局部返回 (return@label)

当 crossinline 禁止非局部返回时,可以使用带标签的返回:

kotlin
inline fun withCrossLambda(
    crossinline lambda: () -> Unit
) {
    lambda()
}

fun main() {
    withCrossLambda {
        // ❌ return  // 错误:非局部返回
        // ✅ return@lambda  // 正确:局部返回(但这里是整个 lambda,所以没必要)
        println("This works")
    }
    
    // 对于带参数的 lambda
    listOf(1, 2, 3).forEach { item ->
        if (item == 2) {
            return@forEach  // ✅ 局部返回,跳出 forEach
        }
        println(item)
    }
}

5. 内联属性

5.1 什么是内联属性

从 Kotlin 1.6 开始,支持内联属性(inline properties),它可以内联 getter 和 setter,进一步优化性能。

kotlin
// 内联属性
inline val Int.isEven: Boolean
    get() = this % 2 == 0

inline val Int.isOdd: Boolean
    get() = this % 2 != 0

fun main() {
    println(4.isEven)  // true - getter 被内联
    println(5.isOdd)   // true - getter 被内联
}

5.2 内联扩展属性

kotlin
// 扩展属性
inline val String.firstCharUpper: String
    get() = this.firstOrNull()?.let { it.uppercase() } + this.drop(1)

inline val List<Int>.sumOfSquares: Int
    get() = this.sumOf { it * it }

inline val Collection<*>.sizeInKB: Int
    get() = this.size * 1024

fun main() {
    println("hello".firstCharUpper)  // "Hello"
    println(listOf(1, 2, 3).sumOfSquares)  // 14
    println(listOf(1, 2, 3).sizeInKB)  // 3072
}

5.3 内联可变属性

kotlin
class Counter {
    private var _count = 0
    
    // 内联属性访问器
    inline var count: Int
        get() = _count
        set(value) {
            require(value >= 0) { "Count cannot be negative" }
            _count = value
        }
}

fun main() {
    val counter = Counter()
    counter.count = 10  // setter 被内联
    println(counter.count)  // getter 被内联
}

5.4 内联委托属性

kotlin
// 内联委托
inline fun <T> lazyInline(initializer: () -> T): Lazy<T> =
    lazy { initializer() }

class Example {
    val data: String by lazyInline {
        println("Computing...")
        "Computed value"
    }
}

fun main() {
    val example = Example()
    println(example.data)  // getter 被内联
    println(example.data)  // 使用缓存值
}

5.5 性能对比

kotlin
// 普通属性
val Int.isEvenNormal: Boolean
    get() = this % 2 == 0

// 内联属性
inline val Int.isEvenInline: Boolean
    get() = this % 2 == 0

fun benchmark() {
    val numbers = 1..1000000
    val iterations = 1000
    
    // 普通属性
    val normalStart = System.nanoTime()
    repeat(iterations) {
        numbers.count { it.isEvenNormal }
    }
    val normalEnd = System.nanoTime()
    
    // 内联属性
    val inlineStart = System.nanoTime()
    repeat(iterations) {
        numbers.count { it.isEvenInline }
    }
    val inlineEnd = System.nanoTime()
    
    println("Normal: ${(normalEnd - normalStart) / 1_000_000} ms")
    println("Inline: ${(inlineEnd - inlineStart) / 1_000_000} ms")
    // 内联属性通常快 20-30%
}

5.6 使用限制

kotlin
// ❌ 错误:不能在外部类定义内联属性
class Outer {
    // inline val something: String  // 错误
}

// ✅ 正确:在顶层或对象中定义
inline val TOP_LEVEL: String = "value"

object MyObject {
    inline val PROPERTY: String = "value"
}

// ❌ 错误:内联属性不能访问类的私有成员
class MyClass {
    private val privateVal = "private"
    
    // inline val publicVal: String  // 错误
    //     get() = privateVal
}

6. reified 泛型

6.1 什么是 reified 类型参数

reified(具体化)类型参数允许在运行时访问泛型的实际类型信息。普通泛型在运行时会被擦除,而 reified 类型参数保留了类型信息。

kotlin
// 普通泛型 - 运行时类型擦除
fun <T> isInstance(obj: Any): Boolean {
    // obj is T  // ❌ 错误:T 在运行时不可用
    return obj.javaClass.name == ""  // 无法获取 T 的实际类型
}

// reified 泛型 - 运行时类型可用
inline fun <reified T> isInstance(obj: Any): Boolean {
    return obj is T  // ✅ 可以:T 在运行时可用
}

fun main() {
    println(isInstance<String>("Hello"))  // true
    println(isInstance<Int>("Hello"))     // false
}

6.2 使用条件

使用 reified 的条件:

  1. 函数必须标记为 inline
  2. 类型参数必须标记为 reified
kotlin
// ✅ 正确用法
inline fun <reified T> createInstance(): T {
    // ...
}

// ❌ 错误:非内联函数不能使用 reified
fun <reified T> notAllowed(): T {
    // 编译错误
}

// ❌ 错误:reified 不能用于类
// class Box<reified T>  // 编译错误

6.3 常见应用 1:类型检查

kotlin
inline fun <reified T> List<*>.filterByType(): List<T> {
    return this.filterIsInstance<T>()
}

inline fun <reified T> Any?.castOrNull(): T? {
    return this as? T
}

inline fun <reified T> Collection<*>.containsType(): Boolean {
    return any { it is T }
}

fun main() {
    val mixed = listOf(1, "two", 3.0, true)
    
    println(mixed.filterByType<String>())   // ["two"]
    println(mixed.filterByType<Int>())      // [1]
    
    println(123.castOrNull<String>())      // null
    println(123.castOrNull<Int>())         // 123
    
    println(mixed.containsType<String>())  // true
    println(mixed.containsType<Double>())  // true
}

6.4 常见应用 2:Kotlin 反射替代

kotlin
// 使用 reified 替代反射
inline fun <reified T> KClass<T>.createInstance(): T {
    return T::class.java.getDeclaredConstructor().newInstance()
}

inline fun <reified T> Class<T> isSubclassOf(): Boolean {
    return T::class.java.isSubclassOf(OtherClass::class.java)
}

inline fun <reified T> String.parseAs(): T? {
    return try {
        when {
            T::class == Int::class -> this.toInt() as T
            T::class == Double::class -> this.toDouble() as T
            T::class == Boolean::class -> this.toBoolean() as T
            else -> null
        }
    } catch (e: Exception) {
        null
    }
}

fun main() {
    // 无反射的类型检查
    println(String::class.isSubclassOf<Any>())  // true
    
    // 类型解析
    println("123".parseAs<Int>())           // 123
    println("123.45".parseAs<Double>())     // 123.45
    println("true".parseAs<Boolean>())      // true
}

6.5 常见应用 3:序列化/反序列化

kotlin
// 简化的序列化
inline fun <reified T> jsonToObject(json: String): T? {
    return try {
        // 使用 Gson 或 Jackson
        Gson().fromJson(json, T::class.java)
    } catch (e: Exception) {
        null
    }
}

inline fun <reified T> objectToJson(obj: T): String {
    return Gson().toJson(obj)
}

fun main() {
    data class User(val name: String, val age: Int)
    
    val user = User("Alice", 30)
    val json = objectToJson(user)
    println(json)  // {"name":"Alice","age":30}
    
    val parsed = jsonToObject<User>(json)
    println(parsed)  // User(name=Alice, age=30)
}

6.6 常见应用 4:依赖注入

kotlin
// 简单的 DI 容器
class ServiceLocator {
    private val instances = mutableMapOf<KClass<*>(), Any>()
    
    inline fun <reified T : Any> register(instance: T) {
        instances[T::class] = instance
    }
    
    inline fun <reified T : Any> get(): T? {
        return instances[T::class] as? T
    }
    
    inline fun <reified T : Any> getOrRegister(factory: () -> T): T {
        return get() ?: run {
            val instance = factory()
            register(instance)
            instance
        }
    }
}

// 使用
fun main() {
    val locator = ServiceLocator()
    
    locator.register(Database())
    locator.register(Repository(locator.get<Database>()))
    
    val db = locator.get<Database>()
    val repo = locator.get<Repository>()
}

data class Database
data class Repository(val db: Database)

6.7 常见应用 5:协程中的使用

kotlin
// 协程中的 reified
inline fun <reified T> suspend Flow<T>.firstOrNull(): T? {
    return this.firstOrNull()
}

inline fun <reified T> suspend Flow<T>.filterType(): Flow<T> {
    return this.filter { it is T }.map { it as T }
}

// 收集特定类型的流
inline fun <reified T> Flow<T>.collectByType(
    crossinline action: suspend (T) -> Unit
) {
    this.collect { action(it) }
}

fun main() = runBlocking {
    val flow = flowOf(1, 2, 3, "four", 5)
    
    flow.collectByType<Int> { 
        println("Int: $it") 
    }
}

6.8 高级应用:类型安全的 Builder

kotlin
// 类型安全的 Builder 模式
interface Builder<out T> {
    fun build(): T
}

inline fun <reified T : Any> builder(block: Builder<T>.() -> Unit): T {
    val builder = object : Builder<T> {
        override fun build(): T = TODO()
    }
    builder.block()
    return builder.build()
}

// 使用 reified 的集合操作
inline fun <reified T> List<T>.groupedByType(): Map<String, List<T>> {
    return this.groupBy { it.javaClass.simpleName }
}

inline fun <reified T> Collection<T>.distinctByType(): List<T> {
    return this.distinctBy { it.javaClass }
}

6.9 reified 与继承

kotlin
// reified 可以检查继承关系
inline fun <reified Parent> isSubclassOf(child: Any): Boolean {
    return child::class.isSubclassOf(Parent::class) || child is Parent
}

inline fun <reified T> KClass<out T>.isAssignableFrom(other: KClass<*>): Boolean {
    return T::class.isAssignableFrom(other.java)
}

fun main() {
    open class Animal
    class Dog : Animal()
    
    val dog = Dog()
    println(isSubclassOf<Animal>(dog))  // true
    println(isSubclassOf<Dog>(dog))     // true
    println(isSubclassOf<Cat>(dog))     // false
}

7. 内联函数的限制

7.1 不能递归调用

kotlin
// ❌ 错误:内联函数不能递归调用自身
// inline fun factorial(n: Int): Int {
//     if (n <= 1) return 1
//     return n * factorial(n - 1)  // 编译错误
// }

// ✅ 解决:使用尾递归或普通函数
tailrec fun factorial(n: Int, acc: Int = 1): Int {
    if (n <= 1) return acc
    return factorial(n - 1, n * acc)
}

7.2 代码膨胀问题

kotlin
// 代码膨胀示例
inline fun <T> List<T>.customOperation(action: (T) -> Unit) {
    for (item in this) {
        action(item)
        log("Processed: $item")
    }
}

// 如果在 100 个地方调用,代码会被复制 100 次
// 这会导致:
// 1. 编译时间增加
// 2. 生成的代码体积增大
// 3. 调试困难

// 最佳实践:只在性能敏感的地方使用内联
fun <T> List<T>.customOperation(action: (T) -> Unit) {
    // 普通函数,避免代码膨胀
    for (item in this) {
        action(item)
        log("Processed: $item")
    }
}

7.3 调试困难

kotlin
// 内联函数在调试时的问题
inline fun process(data: List<Int>, transform: (Int) -> Int): List<Int> {
    return data.map(transform)
}

fun main() {
    val result = process(listOf(1, 2, 3)) { it * 2 }
    // 调试时无法在 process 函数中设置断点
    // 因为函数体被展开到调用处
}

// 调试技巧:使用非内联版本
fun <T> List<T>.debugMap(transform: (T) -> Int): List<Int> {
    println("Starting map operation on ${this.size} elements")
    val result = this.map(transform)
    println("Map operation completed")
    return result
}

7.4 堆栈跟踪问题

kotlin
inline fun <T> slowOperation(data: T): T {
    Thread.sleep(1000)
    return data
}

fun main() {
    try {
        slowOperation("test")
    } catch (e: Exception) {
        e.printStackTrace()
        // 堆栈跟踪中可能没有 slowOperation 的帧
        // 因为代码被内联到了调用处
    }
}

// 对比非内联函数
fun <T> nonInlineSlowOperation(data: T): T {
    Thread.sleep(1000)
    return data
}

// 堆栈跟踪会包含 nonInlineSlowOperation 的帧

7.5 内联属性不能访问私有成员

kotlin
class MyClass {
    private val privateField = "private"
    
    // ❌ 错误:内联属性不能访问私有成员
    // inline val publicProp: String
    //     get() = privateField
    
    // ✅ 正确:使用普通属性
    val publicProp: String
        get() = privateField
}

7.6 文件大小限制

kotlin
// 过度使用内联会导致编译文件过大
// 示例:在大型项目中过度内联

inline fun <T> customFilter(predicate: (T) -> Boolean): Boolean {
    // 复杂的过滤逻辑
    // ...
}

inline fun <T> customMap(transform: (T) -> T): T {
    // 复杂的转换逻辑
    // ...
}

inline fun <T> customReduce(accumulator: (T, T) -> T): T {
    // 复杂的归约逻辑
    // ...
}

// 如果这些函数在项目中被频繁调用,会导致:
// 1. 编译时间显著增加
// 2. 生成的 .class 文件体积增大
// 3. JIT 优化负担加重

// 建议:只在性能瓶颈处使用内联

8. 性能对比分析

8.1 基准测试框架

kotlin
@OptIn(ExperimentalStdlibApi::class)
fun <T> measureBlock(label: String, block: () -> T): T {
    // 预热 JVM
    repeat(100) { block() }
    
    val iterations = 10000
    val start = System.nanoTime()
    val result = repeat(iterations) { block() }
    val end = System.nanoTime()
    
    val avgTime = (end - start) / iterations
    println("$label: ${avgTime / 1_000} ns per iteration")
    return result
}

8.2 Lambda 创建开销

kotlin
// 测试 lambda 创建开销
fun testLambdaCreation() {
    val items = List(10000) { it }
    
    // 非内联版本
    measureBlock("Non-inline forEach") {
        items.forEach { println(it) }
    }
    
    // 内联版本
    inline fun <T> List<T>.forEachInline(action: (T) -> Unit) {
        for (item in this) action(item)
    }
    
    measureBlock("Inline forEach") {
        items.forEachInline { println(it) }
    }
}

// 典型结果:
// Non-inline forEach: 150 ns per iteration
// Inline forEach: 80 ns per iteration
// Speedup: 87.5%

8.3 链式调用性能

kotlin
inline fun <T> List<T>.chainOptimized(): List<T> =
    this.filter { it > 0 }
        .map { it * 2 }
        .filter { it < 100 }

fun <T> List<T>.chainStandard(): List<T> =
    this.filter { it > 0 }
        .map { it * 2 }
        .filter { it < 100 }

fun testChaining() {
    val data = List(10000) { it }
    
    measureBlock("Chain optimized") {
        data.chainOptimized()
    }
    
    measureBlock("Chain standard") {
        data.chainStandard()
    }
}

8.4 协程性能对比

kotlin
inline suspend fun <T> processInline(items: List<T>): List<T> {
    return items.map { item ->
        delay(1)
        item
    }
}

suspend fun <T> processNonInline(items: List<T>): List<T> {
    return items.map { item ->
        delay(1)
        item
    }
}

fun testCoroutinePerformance() = runBlocking {
    val items = List(1000) { it }
    
    measureBlock("Coroutine inline") {
        processInline(items)
    }
    
    measureBlock("Coroutine non-inline") {
        processNonInline(items)
    }
}

8.5 内存使用对比

kotlin
fun testMemoryUsage() {
    val gcIterations = 5
    
    // 非内联版本
    repeat(gcIterations) { System.gc() }
    val beforeNonInline = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    
    val data = List(100000) {
        List(10) { it }.map { it * 2 }
    }
    
    repeat(gcIterations) { System.gc() }
    val afterNonInline = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    
    // 内联版本
    repeat(gcIterations) { System.gc() }
    val beforeInline = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    
    inline fun <T> innerInline(items: List<Int>): List<Int> {
        return items.map { it * 2 }
    }
    
    val dataInline = List(100000) {
        List(10) { it }.let { innerInline(it) }
    }
    
    repeat(gcIterations) { System.gc() }
    val afterInline = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
    
    println("Non-inline memory: ${afterNonInline - beforeNonInline} bytes")
    println("Inline memory: ${afterInline - beforeInline} bytes")
}

8.6 编译时间对比

kotlin
// 编译时间测试脚本(外部脚本)
/*
# test_compile_time.sh
# 非内联版本
time kotlinc main.kt -include-runtime -d non-inline.jar

# 内联版本
time kotlinc main.kt -include-runtime -d inline.jar
*/

9. 最佳实践

9.1 何时使用内联

kotlin
// ✅ 适合内联的场景:
// 1. 接受 lambda 的高阶函数
inline fun <T> List<T>.forEachOptimized(action: (T) -> Unit) {
    for (item in this) action(item)
}

// 2. 性能敏感的代码
inline fun compute-intensive(x: Int): Int {
    return x * x + x / 2
}

// 3. 使用 reified 泛型
inline fun <reified T> isOfType(value: Any): Boolean = value is T

// 4. 简单的扩展函数
inline val Int.doubled: Int get() = this * 2

9.2 何时避免内联

kotlin
// ❌ 不适合内联的场景:
// 1. 复杂函数体
fun complexFunction(data: List<Data>) {
    // 大量逻辑
    // 不应该内联
}

// 2. 递归函数
fun factorial(n: Int): Int {
    if (n <= 1) return 1
    return n * factorial(n - 1)
}

// 3. 被频繁调用但逻辑简单的函数
fun simpleCheck(value: Int): Boolean = value > 0

// 4. 需要调试和堆栈跟踪的函数
fun debuggableFunction(data: Data) {
    // 需要断点调试
}

9.3 性能优化建议

kotlin
// 1. 只内联小函数
inline fun smallInline(x: Int): Int = x * 2

// 2. 使用内联减少 lambda 创建
inline fun <T> List<T>.process(action: (T) -> Unit) {
    for (item in this) action(item)
}

// 3. 避免过度内联导致代码膨胀
fun <T> notInlined(items: List<T>) {
    // 复杂逻辑,保持为普通函数
}

// 4. 在性能关键路径使用内联
inline fun performanceCritical(data: ByteArray): Int {
    var sum = 0
    for (byte in data) sum += byte
    return sum
}

9.4 代码组织

kotlin
// 组织内联函数的最佳位置
// 1. 工具类/对象
object Utils {
    inline fun <T> List<T>.customFilter(predicate: (T) -> Boolean): List<T> {
        return filter(predicate)
    }
}

// 2. 扩展函数文件
// InlineExtensions.kt
inline fun <T> Iterable<T>.measureTime(block: () -> T): T {
    val start = System.currentTimeMillis()
    val result = block()
    println("Took: ${System.currentTimeMillis() - start}ms")
    return result
}

// 3. 性能关键模块
// PerformanceCritical.kt
inline fun <T> batchProcess(items: List<T>, processor: (T) -> T): List<T> {
    return items.map(processor)
}

10. 常见错误与陷阱

10.1 忘记内联 lambda 参数

kotlin
// ❌ 错误:lambda 参数没有内联
inline fun wrongExample(lambda: () -> Unit) {
    lambda()  // lambda 不会被内联
}

// ✅ 正确:Kotlin 自动内联 lambda 参数
inline fun correctExample(lambda: () -> Unit) {
    lambda()  // lambda 会被内联
}

10.2 在非内联函数使用 reified

kotlin
// ❌ 错误
// fun <reified T> getTypeName(): String {
//     return T::class.simpleName
// }

// ✅ 正确
inline fun <reified T> getTypeName(): String {
    return T::class.simpleName
}

10.3 过度使用导致代码膨胀

kotlin
// ❌ 过度使用
inline fun helper1(x: Int): Int = x + 1
inline fun helper2(x: Int): Int = x * 2
inline fun helper3(x: Int): Int = x / 2

fun main() {
    repeat(1000) { i ->
        helper1(i)
        helper2(i)
        helper3(i)
    }
}
// 代码被复制 3000 次

// ✅ 适度使用
fun helper1(x: Int): Int = x + 1
fun helper2(x: Int): Int = x * 2
inline fun helper3(x: Int): Int = x / 2  // 只在性能关键处内联

10.4 调试困难

kotlin
inline fun complexOperation(data: Data): Result {
    // 复杂的业务逻辑
    // ...
}

fun main() {
    // 调试时无法在 complexOperation 设置断点
    val result = complexOperation(data)
}

// ✅ 调试技巧:使用普通函数版本
fun complexOperationDebug(data: Data): Result {
    // 可以设置断点
}

11. 高级应用场景

11.1 DSL 构建

kotlin
// DSL 构建示例
inline fun html(init: HtmlBuilder.() -> Unit): String {
    val builder = HtmlBuilder()
    builder.init()
    return builder.build()
}

class HtmlBuilder {
    private val buffer = StringBuilder()
    
    inline fun html(init: HtmlBuilder.() -> Unit) {
        buffer.append("<html>")
        init()
        buffer.append("</html>")
    }
    
    inline fun body(init: HtmlBuilder.() -> Unit) {
        buffer.append("<body>")
        init()
        buffer.append("</body>")
    }
    
    inline fun div(attrs: Map<String, String> = emptyMap(), init: HtmlBuilder.() -> Unit) {
        buffer.append("<div")
        attrs.forEach { (k, v) ->
            buffer.append(" $k=\"$v\"")
        }
        buffer.append(">")
        init()
        buffer.append("</div>")
    }
    
    fun build() = buffer.toString()
}

fun main() {
    val htmlString = html {
        html {
            body {
                div(mapOf("class" to "container")) {
                    p { "Hello World" }
                }
            }
        }
    }
    println(htmlString)
}

11.2 领域特定语言

kotlin
// 查询 DSL
inline fun <T> QueryBuilder<T>.where(crossinline condition: T.() -> Boolean) {
    // 构建查询条件
}

inline fun <T> QueryBuilder<T>.select(crossinline fields: List<KProperty1<T, *>>) {
    // 选择字段
}

// 使用
val query = QueryBuilder<User>()
    .where { it.age > 18 }
    .select(listOf(User::name, User::email))

11.3 测试框架

kotlin
// 自定义测试框架
inline fun <reified T> test(name: String, crossinline testBlock: () -> Unit) {
    println("Running test: $name")
    try {
        testBlock()
        println("✓ $name passed")
    } catch (e: AssertionError) {
        println("✗ $name failed: ${e.message}")
    }
}

inline fun <reified T> assertTrue(condition: Boolean, message: String = "") {
    if (!condition) {
        throw AssertionError(message)
    }
}

fun main() {
    test("User creation") {
        val user = User("Alice", 30)
        assertTrue(user.name == "Alice")
        assertTrue(user.age == 30)
    }
}

12. 面试考点

12.1 基础考点

Q1: 什么是内联函数?它有什么作用?

A:

  • 内联函数使用 inline 关键字标记
  • 编译时将函数体代码直接复制到调用点
  • 主要作用是消除 lambda 对象创建,提高性能
  • 避免了函数调用开销

Q2: 内联函数和普通函数的区别?

A:

特性普通函数内联函数
调用方式函数调用指令代码复制
lambda 对象创建对象不创建
性能较慢更快
代码大小可能膨胀
调试容易困难

Q3: 内联函数的 lambda 参数会被内联吗?

A: 会。内联函数的 lambda 参数默认都会被内联,除非使用 noinline 修饰。

12.2 进阶考点

Q4: noinline 和 crossinline 的区别?

A:

  • noinline: 阻止 lambda 被内联,允许保存 lambda 引用
  • crossinline: lambda 会被内联,但禁止非局部返回

Q5: reified 类型参数的使用条件?

A:

  1. 函数必须是 inline
  2. 类型参数必须标记为 reified
  3. 只能在内联函数中使用

Q6: 内联函数的性能优势?

A:

  1. 消除 lambda 对象创建(主要优势)
  2. 避免函数调用开销
  3. 更好的 JIT 优化机会
  4. 减少内存分配

12.3 高级考点

Q7: 实现一个支持类型安全的 JSON 解析器

A:

kotlin
inline fun <reified T> parseJson(json: String): T {
    return Gson().fromJson(json, T::class.java)
}

inline fun <reified T> toJson(obj: T): String {
    return Gson().toJson(obj)
}

fun main() {
    data class User(val name: String, val age: Int)
    
    val user = User("Alice", 30)
    val json = toJson(user)
    val parsed = parseJson<User>(json)
}

Q8: 设计一个性能优化的集合操作库

A:

kotlin
// 内联集合操作
inline fun <T, R> List<T>.mapInline(transform: (T) -> R): List<R> {
    val result = ArrayList<R>(this.size)
    for (item in this) {
        result.add(transform(item))
    }
    return result
}

inline fun <T> List<T>.filterInline(predicate: (T) -> Boolean): List<T> {
    val result = ArrayList<T>()
    for (item in this) {
        if (predicate(item)) {
            result.add(item)
        }
    }
    return result
}

inline fun <T> List<T>.forEachInline(action: (T) -> Unit) {
    for (item in this) {
        action(item)
    }
}

Q9: 内联函数在协程中的优势?

A:

  1. 减少协程状态机的复杂度
  2. 避免在挂起点创建额外对象
  3. 降低协程内存占用
  4. 更好的性能表现

Q10: 内联函数的限制和最佳实践?

A:

限制:

  • 不能递归调用
  • 代码膨胀
  • 调试困难
  • 堆栈跟踪问题

最佳实践:

  • 只在性能关键路径使用
  • 避免过度内联
  • 保持函数体简单
  • 考虑可维护性

总结

内联函数是 Kotlin 提供的强大性能优化工具,通过消除 lambda 对象创建和函数调用开销,显著提升性能。掌握内联函数、noinline、crossinline 和 reified 泛型的使用,对于编写高性能的 Kotlin 代码至关重要。

核心要点:

  1. inline - 消除 lambda 对象创建
  2. noinline - 阻止特定 lambda 内联
  3. crossinline - 禁止非局部返回
  4. reified - 运行时类型信息
  5. 性能权衡 - 代码膨胀 vs 性能提升