1. Kotlin 中的 map() 方法

Kotlin 中的 map() 方法是一个强大的函数式编程工具,可用于对数组中的元素进行转换。但 map() 并不会修改原始数组,而是返回一个包含转换后结果的新数组。

例如,我们可以使用 map() 将数组中的每个元素翻倍:

@Test
fun `Should map an array by doubling all numbers`() {
    val numbers = arrayOf(1, 2, 3, 4, 5)
    val doubledNumbers = numbers.map { it * 2 }

    assertContentEquals(listOf(2, 4, 6, 8, 10), doubledNumbers)
}

上面的代码中,map() 方法返回了一个新数组,原始数组 numbers 并未被修改。

如果我们确实想让原始变量指向新的数组,可以像下面这样操作:

@Test
fun `Should reassign the original variable to the new array`() {
    var numbers = arrayOf(1, 2, 3, 4, 5)
    numbers = numbers.map { it * 2 }.toTypedArray()

    assertContentEquals(arrayOf(2, 4, 6, 8, 10), numbers)
}

✅ 这种方式适用于我们希望保留原始变量名,但指向新数组的情况。


2. 原地修改数组

如果我们希望 直接修改原始数组 而不创建新数组,可以考虑写一个扩展函数,实现类似 map() 的功能,但作用在原数组上。

fun <T> Array<T>.mapInPlace(transform: (T) -> T): Array<T> {
    for (i in this.indices) {
        this[i] = transform(this[i])
    }
    return this
}

使用示例:

@Test
fun `Should replace array values in the original array`() {
    val numbers = arrayOf(1, 2, 3, 4, 5)
    numbers.mapInPlace { it * 2 }

    assertContentEquals(arrayOf(2, 4, 6, 8, 10), numbers)
}

⚠️ 这种方式虽然性能更好,但会破坏不可变性(immutability),属于副作用操作,需谨慎使用


3. map() 与 mapInPlace 的优缺点对比

3.1. 使用 map() 的优缺点

优点:

  • 不可变性保障:不会修改原始数组,避免副作用
  • 表达清晰:一行代码即可完成转换,语义明确
  • 函数式风格:符合函数式编程范式,易于组合和测试

缺点:

  • 内存开销大:每次转换都生成新数组,大数据量下可能影响性能
  • 中间集合过多:链式调用时会产生多个中间集合,增加 GC 压力

3.2. 使用 mapInPlace 的优缺点

优点:

  • 性能更优:避免创建新数组,节省内存和 CPU
  • 适合特定场景:如处理大型数组时,原地修改更高效

缺点:

  • 破坏不可变性:引入副作用,增加代码复杂度
  • 非函数式风格:不符合现代函数式编程理念,难以维护和测试

4. 小结与建议

在 Kotlin 中,map() 是一个安全、简洁、函数式的方法,适合大多数数组转换场景。它不会修改原始数组,而是返回新数组,这有助于我们写出更清晰、更易维护的代码。

mapInPlace() 则更适合一些特定的高性能场景,比如:

  • 数组非常大,创建新数组代价高
  • 确实不需要保留原始数组
  • 对性能敏感的底层处理逻辑

⚠️ 踩坑提醒: 除非你有明确的理由,否则应优先使用 map(),避免因原地修改带来的副作用和潜在 bug。


完整的示例代码可在 GitHub 上找到。


原始标题:Mutating Arrays in Kotlin