Kotlin Array添加元素失效排查及with/let作用域函数优化方案
Kotlin Array操作失效问题与优化方案
核心诉求
- 定位第一段数组元素添加逻辑不生效的根本原因
- 在不引入冗余逻辑的前提下,实现
Array<>类型的元素新增,替代当前「转MutableList添加元素再转回Array」的冗余写法 - 合理使用Kotlin作用域函数(
with/let/run等)简化代码,无需额外定义clone中间变量即可直接操作program.description.data.options属性
数据结构定义
业务中定义了三层嵌套数据类用于Kotlin序列化,层级关系如下:
- 最外层
FavouriteProgramCommandString包含只读属性val description: FavouriteProgram - 中层
FavouriteProgram包含只读属性val data: FavouriteProgramDetails - 内层
FavouriteProgramDetails包含可变属性var options: Array<FavouriteProgramOptions>
其中FavouriteProgramDetails的定义代码如下:
data class FavouriteProgramDetails( @SerializedName(value = "key", alternate = ["featureKey"]) val key: String, @SerializedName("options") var options: Array<FavouriteProgramOptions>, )
失效代码片段
以下代码中新增元素的逻辑不生效,最终返回的数组和原数组完全一致:
@JvmStatic fun getProgramDescriptionOfFavouritesWithDelayOption( program: FavouriteProgramCommandString, key: String, delayDuration: Double = 0.0, ): FavouriteProgram { with(program.description.data.options) { val nodeOption = firstOrNull { it.key == key } if (nodeOption != null) { this[this.indexOf(nodeOption)].value = delayDuration } else { this.plus(FavouriteProgramOptions(key, delayDuration)) // 新增逻辑不生效 } } return program.description }
临时可用的冗余实现
以下代码可以正常运行,但存在冗余逻辑,不够优雅:
@JvmStatic fun getProgramDescriptionOfFavouritesWithDelayOption2( program: FavouriteProgramCommandString, key: String, delayDuration: Double = 0.0, ): FavouriteProgram { val clone = program.description.data.options.toMutableList() val nodeOption = clone.firstOrNull { it.key == key } if (nodeOption != null) { val index = clone.indexOf(nodeOption) clone[index].value = delayDuration } else { clone.add(FavouriteProgramOptions(key, delayDuration)) // 新增逻辑正常 } program.description.data.options = clone.toTypedArray() return program.description // 返回结果符合预期 }
失效根因
- Kotlin的
Array和Java数组特性一致,是固定长度容器,不支持动态增删元素。plus()、plusElement()方法不会修改原数组实例,只会返回一个包含「原数组所有元素+新增元素」的全新数组。失效代码中调用plus()后既没有接收返回值,也没有将新数组赋值回options属性,原数组自然不会发生任何变化。 - 失效代码中修改已存在元素
value属性的逻辑可以正常运行,是因为这步操作没有改变数组本身的长度、也没有替换数组内存储的元素引用,只是修改了数组中存储的对象的可变属性,和数组增删操作的逻辑完全不同。
最优实现方案
使用run作用域函数简化层级调用,直接操作目标对象,省去冗余中间变量,同时利用数组plus方法的返回值直接赋值,无需重复做集合转换:
@JvmStatic fun getProgramDescriptionOfFavouritesWithDelayOption( program: FavouriteProgramCommandString, key: String, delayDuration: Double = 0.0, ): FavouriteProgram { program.description.data.run { val targetIndex = options.indexOfFirst { it.key == key } if (targetIndex != -1) { options[targetIndex].value = delayDuration } else { options = options.plus(FavouriteProgramOptions(key, delayDuration)) } } return program.description }
该实现的优势:
- 用
run作用域函数将program.description.data作为上下文,省略重复的长路径调用,无需额外定义临时clone变量 - 用
indexOfFirst直接定位目标元素下标,省去「先查找元素、再匹配下标」的两次遍历开销 - 数组新增元素逻辑直接利用
plus返回的新数组赋值,省略了Array -> MutableList -> Array的两次转换步骤,逻辑更简洁
注:Array.plus()方法的底层实现和「转MutableList添加元素再转Array」逻辑一致,都是创建新数组做元素拷贝,性能没有本质差异。
内容的提问来源于stack exchange,提问作者Red Coder
相关产品推荐
相关产品推荐

