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

 更新时间:2025年07月24日 10:11:59   作者:说码解字  
Kotlin 中的let是一个,它广泛用于作用域函数(Scope Functions)中,尤其适用于对可空对象(nullable)做非空判断并执行代码块的场景,本文给大家介绍Kotlin 作用域函数 let 的实现原理,感兴趣的朋友一起看看吧

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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • android中实现指针滑动的动态效果方法

    android中实现指针滑动的动态效果方法

    本次实现的是类似于墨迹天气中轨迹图片上指针随着数值滚动滑动的效果,基本思路是开启线程,控制指针所在的imageview控件的padding属性。
    2013-03-03
  • Android开发之登录验证实例教程

    Android开发之登录验证实例教程

    这篇文章主要介绍了Android开发之登录验证实现方法,包括发送数据、服务器端验证、配置文件等,需要的朋友可以参考下
    2014-08-08
  • Android 创建依赖库的方法(保姆级教程)

    Android 创建依赖库的方法(保姆级教程)

    这篇文章主要介绍了Android 创建依赖库的方法(保姆级教程),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Android使用HBuilder的缓存方法

    Android使用HBuilder的缓存方法

    这篇文章主要介绍了Android使用HBuilder的缓存方法 ,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-12-12
  • Android12四大组件之Activity生命周期变化详解

    Android12四大组件之Activity生命周期变化详解

    虽然说我们天天都在使用Activity,但是你真的对Activity的生命机制完全了解了吗?Activity的生命周期方法只有七个,但是其实那只是默认的情况。也就是说在其他情况下,Activity的生命周期可能不会是按照我们以前所知道的流程,本章着重讲解Activity的生命周期变化
    2022-07-07
  • Jetpack之CameraX的使用

    Jetpack之CameraX的使用

    CameraX 是Jetpack的一个成员,可以更轻松地开发相机应用,支持搭载Android 5.0及以上设备,具有广泛的设备兼容性,也可确保各设备间的一致性,如宽高比、屏幕方向、旋转角度、预览大小和图像大小等
    2022-11-11
  • Android入门之日历选择与时间选择组件的使用

    Android入门之日历选择与时间选择组件的使用

    这篇文章主要为大家详细介绍了Android中TimePicker时间选择与DatePicker日期选择组件的使用方法,文中的示例代码讲解详细,需要的朋友可以参考下
    2022-11-11
  • Kotlin面向对象知识点讲解

    Kotlin面向对象知识点讲解

    面向对象编程通过对事物的抽象,大大的简化了程序的开发难度。我们常用的编程语言:Java、C++、Python都属于面向对象编程。Kotlin与java类似,也是一种面向对象编程语言。本文从面向对象三个基本特征:封装、继承、多态,来阐述一下Kotlin中的面向对象编程
    2022-12-12
  • Android开发实现图片平移、缩放、倒影及旋转功能的方法

    Android开发实现图片平移、缩放、倒影及旋转功能的方法

    这篇文章主要介绍了Android开发实现图片平移、缩放、倒影及旋转功能的方法,涉及Android针对图片的读取、写入、属性设置及矩阵运算等相关操作技巧,需要的朋友可以参考下
    2017-10-10
  • Android判断用户2G/3G/4G移动数据网络

    Android判断用户2G/3G/4G移动数据网络

    这篇文章主要介绍了Android判断用户2G/3G/4G移动数据网络的方法,感兴趣的小伙伴们可以参考一下
    2015-12-12

最新评论