我有一个清单:
val someList = listOf(1, 20, 10, 55, 30, 22, 11, 0, 99)
我想在修改一些值时迭代它 . 我知道我可以用 map
来做,但是它会复制一份列表 .
val copyOfList = someList.map { if (it <= 20) it + 20 else it }
如果没有副本我该怎么办?
Note: 这个问题是由作者故意编写和回答的(Self-Answered Questions),因此对于常见的Kotlin主题的惯用答案存在于SO中 . 还要澄清为Kotlin的alphas写的一些非常古老的答案,这些答案对于当前的Kotlin来说是不准确的 .
1 回答
首先,并非所有复制列表都是错误的 . 有时副本可以利用CPU缓存并且速度非常快,这取决于列表,大小和其他因素 .
其次,要修改列表"in-place",您需要使用一种可变的列表 . 在您的示例中,您使用
listOf
返回List<T>
接口,这是只读的 . 您需要直接引用可变列表的类(即ArrayList
),或者是惯用的Kotlin使用辅助函数arrayListOf
或linkedListOf
来创建MutableList<T>
引用 . 完成后,您可以使用具有突变方法set()
的listIterator()
迭代列表 .这将在迭代发生时更改列表中的值,并且对所有列表类型都有效 . 为了使这更容易,创建有用的扩展功能,您可以重复使用(见下文) .
使用简单的扩展函数进行变异:
您可以为Kotlin编写扩展函数,为任何
MutableList
实现执行可变迭代迭代 . 这些内联函数的执行速度与迭代器的任何自定义使用速度一样快,内联函数也是如此 . 适合Android或任何地方 .这是一个
mapInPlace
扩展函数(它保留了这些类型函数的典型命名,例如map
和mapTo
):Example 调用此扩展函数的任何变体:
这并不适用于所有
Collection<T>
,因为大多数迭代器只有remove()
方法,而不是set()
.数组的扩展函数
您可以使用类似的方法处理通用数组:
对于每个原始数组,使用以下变体:
关于仅使用参考等式的优化
上面的扩展函数通过不设置值(如果它没有更改为其他实例)进行优化,检查使用
===
或!==
是Referential Equality . 不值得检查equals()
或hashCode()
因为调用它们的成本未知,并且参考相等性实际上捕获了更改值的任何意图 .扩展功能的单元测试
以下是显示函数工作的单元测试用例,以及与复制的stdlib函数
map()
的小比较: