You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin问题:复制Map时withDefault默认值未被保留

Kotlin中Map.withDefault默认值复制后丢失的原因解析

为什么默认值包装在复制时不被保留?

  • withDefault 方法不会修改原Map对象,而是返回一个名为MapWithDefault的包装类实例。这个包装类仅负责拦截getValue调用,当键不存在时触发默认值逻辑,但它本身不存储任何键值对,所有数据都指向底层的原Map。
  • 调用toMap()时,方法会遍历包装类持有的底层Map的所有键值对,创建一个新的标准Map实现(比如HashMap)。而MapWithDefault的默认值逻辑属于包装类自身,不会被带入新创建的标准Map——因为标准Map并没有内置存储默认值的机制。

这是预期行为吗?

是的,这完全符合Kotlin的设计预期。withDefault的定位是为单次或局部的getValue调用提供临时默认逻辑,而非让Map本身永久绑定默认值。官方设计逻辑中,默认值仅在通过该包装类调用getValue时生效,所有涉及Map数据复制、遍历的操作,都只会作用于底层的原始Map数据。

容易忽略的细节

  • MapWithDefault是装饰器模式的实现,它实现了Map接口,但所有不涉及getValue的操作(比如containsKey、entries遍历)都会直接转发给底层Map。
  • 如果需要在复制后保留默认值逻辑,有两种方案:
    1. 直接传递MapWithDefault实例,不调用toMap()(如果场景允许直接使用这个包装类)
    2. 在复制后的新Map上重新调用withDefault:
      val mapCopy = map.toMap().withDefault { 0 }
      
  • 另外,getOrDefault方法和withDefault的getValue逻辑不同:getOrDefault是每次调用时显式传入默认值,不依赖包装类,所以复制后的Map也可以正常使用:
    mapCopy.getOrDefault(1, 0) // 同样返回0
    

复现代码

@Test
fun `withDefault not preserved when copying a map`() {
    val map = mapOf<Int, Int>().withDefault { 0 }
    assertEquals(map.getValue(1), 0)

    val mapCopy = map.toMap()
    assertThrows<NoSuchElementException> { mapCopy.getValue(1) }
}

内容的提问来源于stack exchange,提问作者Anaís Solís

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:05:04