Kotlin中如何高效切片vararg参数?
Kotlin嵌套JSON对象扩展函数的vararg参数优化方案
问题描述
我编写了一个扩展函数,用于根据名称获取JSON对象的元素:
fun JSONObject.obj (name: String): JSONObject? = try { this.getJSONObject(name) } catch (e: JSONException) { null }
现在想将其扩展到嵌套JSON对象,于是编写了以下代码:
tailrec fun JSONObject.obj (first: String, vararg rest: String): JSONObject? = if (rest.size == 0) obj(first) else obj(first)?.obj(rest[0], *rest.drop(1).toTypedArray())
但这段代码效率很低,请问切片vararg参数的最优方法是什么?
优化方案
核心问题:避免频繁创建数组
当前实现每次递归都调用rest.drop(1).toTypedArray(),这会反复生成新数组,带来不必要的内存分配和GC开销。最优思路是直接操作原数组的索引,或者用循环替代递归,彻底避免数组切片操作。
方案1:索引式尾递归(保留尾递归特性)
重构为带索引参数的私有辅助函数,对外暴露的入口函数传递初始索引:
fun JSONObject.obj(vararg keys: String): JSONObject? { tailrec fun traverse(current: JSONObject?, index: Int): JSONObject? { if (index >= keys.size) return current val next = current?.obj(keys[index]) ?: return null return traverse(next, index + 1) } return traverse(this, 0) }
如果要保留原函数“第一个参数单独、后续vararg”的结构,可以调整为:
tailrec fun JSONObject.obj(first: String, vararg rest: String): JSONObject? { val allKeys = arrayOf(first, *rest) tailrec fun traverse(current: JSONObject?, index: Int): JSONObject? { if (index >= allKeys.size) return current val next = current?.obj(allKeys[index]) ?: return null return traverse(next, index + 1) } return traverse(this, 0) }
方案2:循环实现(性能最优)
直接用循环替代递归,逻辑更直观,且完全没有递归调用和数组切片的额外开销:
fun JSONObject.obj(vararg keys: String): JSONObject? { var current: JSONObject? = this for (key in keys) { current = current?.obj(key) ?: break } return current }
优化效果说明
- 两种方案都避免了原实现中反复创建数组的问题,大幅减少内存开销。
- 循环实现的性能略优于尾递归(尽管Kotlin会把尾递归优化为循环,但循环写法本身更直接)。
- 所有方案都保留了原函数的空安全特性,遇到不存在的键时直接返回
null。
内容的提问来源于stack exchange,提问作者ceving
相关产品推荐
相关产品推荐

