当前位置: 代码网 > it编程>编程语言>Asp.net > Kotlin 作用域函数 let 的实现原理示例解析

Kotlin 作用域函数 let 的实现原理示例解析

2025年07月24日 Asp.net 我要评论
kotlin 中的 let 是一个 标准库扩展函数,它广泛用于作用域函数(scope functions)中,尤其适用于对可空对象(nullable)做非空判断并执行代码块的场景。示例代码val na

kotlin 中的 let 是一个 标准库扩展函数,它广泛用于作用域函数(scope functions)中,尤其适用于对可空对象(nullable)做非空判断并执行代码块的场景。

示例代码

val name: string? = "123"
name?.let {
    println(it)
}

这个例子等价于:

if (name != null) {
    val it = name
    println(it)
}

也就是说,name?.let { ... } 只有当 name 非空时才执行 let 的 lambda 块。lambda 表达式中 it 就是 name 的非空值。let 返回 lambda 的返回值。

实现原理

kotlin 的 let 函数定义在 commonmain/kotlin/util/standard.kt 中,源码如下:

@kotlin.internal.inlineonly
public inline fun <t, r> t.let(block: (t) -> r): r {
    contract {
        callsinplace(block, invocationkind.exactly_once)
    }
    return block(this)
}

它是一个 内联(inline)函数,在编译时会被内联展开,避免 lambda 带来的性能开销。泛型 <t, r> 表示接收一个类型为 t 的对象,返回一个类型为 r 的结果。t.let 表示 let 是类型 t 的扩展函数。block: (t) -> r 是接收 t 的函数(lambda 表达式)。也就是说,它只是将当前对象 this 传入了 block(this) 中。

@kotlin.internal.inlineonly,这是一个 注解(annotation),用于标记某个函数 只能在被 inline(内联)时使用,否则编译器会报错。

比如下面的代码:

@inlineonly
inline fun <t> t.let(block: (t) -> unit): unit {
    block(this)
}

表示这个 let 函数 不会生成实际函数调用(它只能内联展开),避免 java 或非 kotlin 编译器调用这个方法。

为什么要限制只能 inline?为了提高性能,避免生成函数对象和调用开销,同时 确保代码安全地被内联使用,防止其他模块通过反射或 java 调用这个方法。

contract {
    callsinplace(block, invocationkind.exactly_once)
}

这是kotlin 的 contract dsl,用于 给编译器更多关于 lambda 执行行为的信息,提升智能分析、空安全和优化。表示block 这个 lambda 参数,在函数调用过程中会 被调用且只调用一次(exactly once)。这使得编译器可以进行一些静态分析优化,例如在下面这种空检查中,判断 name 非空:

val name: string? = "abc"
name?.let {
    // 编译器知道这里 it 一定非空,不会再要求你加 !!
    println(it.length) // 安全
}

invocationkind 类型说明:

  • exactly_once:block 会被调用且仅一次
  • at_least_once:一定会调用一次或多次
  • at_most_once:最多一次,可能不调用
  • unknown:不确定

编译器依靠这个信息进行控制流分析,提升非空智能推断、性能优化、检测死代码等能力。

r 是泛型返回类型。

inline fun <t, r> t.let(block: (t) -> r): r {
    return block(this)
}

<t, r> 是泛型声明,t是调用 let 的对象类型(接收者),rblock 函数返回值的类型,也是 let 函数的最终返回值类型。

举例:

val name = "abc"
val length: int = name.let { it.length } // block 返回 int,所以 r = int

也可以是任意类型:

val upper = "abc".let { it.uppercase() } // r = string
val printresult = "abc".let { println(it) } // r = unit

编译后字节码

比如:

val name: string? = "123"
name?.let {
    println(it)
}

大致翻译成 java 是:

string name = "123";
if (name != null) {
    system.out.println(name);
}

编译器把 ?.let { ... } 直接转成了 if != null 的判断。lambda 是内联展开的,不会有额外函数对象生成,所以效率非常高。

常见用途

处理 nullable 类型

val name: string? = getname()
name?.let {
    println("非空值是:$it")
}

链式调用

val result = listof(1, 2, 3).map { it * 2 }.let {
    it.jointostring()
}

限定作用域变量(避免变量污染):

val userinput = readline()
userinput?.let {
    val trimmed = it.trim()
    println("你输入的是:$trimmed")
}
// trimmed 在此作用域外不可见

到此这篇关于kotlin 作用域函数 let 的实现原理的文章就介绍到这了,更多相关kotlin 作用域函数 let内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com