咨询Kotlin标准函数run、with、let、also、apply的正确用法
首先得夸一句,你把原始代码改成用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

