You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询Kotlin标准函数run、with、let、also、apply的正确用法

Kotlin标准函数run/with/let/also/apply用法解析(结合HttpURLConnection示例)

首先得夸一句,你把原始代码改成用run的写法完全找对了路子!先把你的原始代码和优化后的run版本摆出来对比,咱们再逐个拆解这些函数的核心用法:

原始代码:

con = urlGet.openConnection() as HttpURLConnection
con.readTimeout = 10000
con.connectTimeout = 2000
con.requestMethod = "GET"
con.doInput = true
con.connect()
inst = con.inputStream

你用run优化后的完整版本:

con = urlGet.openConnection() as HttpURLConnection
val inputStream = con.run {
    readTimeout = 10000
    connectTimeout = 2000
    requestMethod = "GET"
    doInput = true
    connect()
    inputStream // run会返回代码块最后一行的结果
}

接下来咱们把这几个标准函数的适用场景掰碎了说,帮你彻底搞清楚什么时候用哪个:

1. apply:对象初始化+返回自身

如果你核心需求是给对象做一堆配置,最后还要保留这个对象本身,apply是最优解。它的逻辑就是「在对象的上下文里执行配置代码,最后把原对象吐出来」,完美替代Builder模式:

val con = (urlGet.openConnection() as HttpURLConnection).apply {
    readTimeout = 10000
    connectTimeout = 2000
    requestMethod = "GET"
    doInput = true
    connect()
}
val inputStream = con.inputStream

这种写法链式调用下来,完全不用重复写con.xxx,清爽得很。

2. run:对象上下文+返回结果

就像你用的那样,run和apply的区别在于它返回的是代码块最后一行的结果,不是对象本身。当你需要在配置完对象后,直接拿到某个衍生值(比如这里的inputStream),用run能把「配置+取值」合并成一步,少写临时变量。

3. with:非扩展版的run

with其实就是run的非扩展函数形式,用法几乎一致,只是调用方式不同:

val inputStream = with(con) {
    readTimeout = 10000
    connectTimeout = 2000
    requestMethod = "GET"
    doInput = true
    connect()
    inputStream
}

如果对象已经提前创建好了,用with和run都行;但如果是刚new出来的对象,用run的链式调用会更流畅。

4. let:安全调用+结果转换

let的核心优势是处理可空对象,同时支持把对象转换成其他结果。比如如果urlGet.openConnection()可能返回null,你可以这么写:

val inputStream = (urlGet.openConnection() as? HttpURLConnection)?.let { con ->
    con.readTimeout = 10000
    con.connectTimeout = 2000
    con.requestMethod = "GET"
    con.doInput = true
    con.connect()
    con.inputStream
}

?.let确保只有对象非空时才执行代码块,而且你可以给参数自定义名字(比如这里的con),比默认的it更清晰。和run的区别是,let更偏向「处理可空+转换结果」,而run偏向「配置+取值」。

5. also:对象上下文+返回自身+副作用处理

also和apply一样返回对象本身,但它用it指代当前对象,更适合在配置对象的同时执行一些「副作用」操作(比如打日志、埋点),而不是直接修改对象属性:

val con = (urlGet.openConnection() as HttpURLConnection).also {
    println("正在配置连接:${it.url}")
}.apply {
    readTimeout = 10000
    connectTimeout = 2000
    requestMethod = "GET"
    doInput = true
    connect()
}

简单说就是:apply管修改对象配置,also管额外的附属操作,分工明确。

最后给你个快速记忆的小口诀:

  • 配置对象留对象:apply
  • 配置对象拿结果:run
  • 可空处理转结果:let
  • 附加操作留对象:also
  • 已有对象拿结果:with

内容的提问来源于stack exchange,提问作者LiTTle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:43:56