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

Groovy列表迭代与Map更新异常:仅保留最后元素值问题

问题分析与解决方案

问题根源

这是因为Groovy(和Java一致)中可变对象按引用传递,你的代码只做了浅拷贝,导致多个phase共享了同一个可变对象引用:

1. 为什么id字段更新正常

  • phase.id = id是给每个独立的phase Map新增键值对,每个phase都是单独的Map实例,彼此互不干扰。
  • 模板中的type是字符串,属于不可变类型,赋值时传递的是引用,但由于字符串不可修改,所以每个phase的type都能保持正确值。

2. 为什么directories字段更新异常

  • template.directories是列表,列表内的元素是Map,二者都是可变对象。你通过phase.put(it, template.get(it))复制时,只是把template.directories的引用赋值给了phase.directories——所有phase的directories都指向同一个列表,列表内的Map也是同一个实例。
  • 每次迭代修改phase.directories[0].put('command', ...)时,都是在修改同一个底层Map,最后一次迭代(id=3)的修改会覆盖之前所有操作,导致所有phase的directories都显示最后一个值。

解决方案

需要对模板中的可变对象做深拷贝,确保每个phase拥有独立的可变对象实例,以下是几种可行方法:

方法一:手动深拷贝可变对象

针对模板中的可变字段单独处理,复制列表及内部的Map:

def template = [type: 'a', directories: [['dir': 'a/b/c']]]
def ids = [1,2,3]
def allPhases = []

ids.each { id ->
    def phase = [:]
    // 复制不可变类型字段
    phase.type = template.type
    // 深拷贝directories列表及内部的Map
    phase.directories = template.directories.collect { it.clone() }
    phase.id = id
    phase.directories[0].put('command', "apply/${id}")
    allPhases.add(phase)
}
println(allPhases)

方法二:使用Groovy内置的deepCopy方法(Groovy 2.5+)

直接对整个模板做深拷贝,自动处理所有嵌套的可变对象:

def template = [type: 'a', directories: [['dir': 'a/b/c']]]
def ids = [1,2,3]
def allPhases = []

ids.each { id ->
    // 深拷贝生成独立的模板实例
    def phase = template.deepCopy()
    phase.id = id
    phase.directories[0].put('command', "apply/${id}")
    allPhases.add(phase)
}
println(allPhases)

方法三:结合Map的clone与列表拷贝

先克隆模板Map,再单独拷贝可变的directories字段:

def template = [type: 'a', directories: [['dir': 'a/b/c']]]
def ids = [1,2,3]
def allPhases = []

ids.each { id ->
    def phase = template.clone()
    // 重新拷贝directories,避免引用共享
    phase.directories = phase.directories.collect { it.clone() }
    phase.id = id
    phase.directories[0].put('command', "apply/${id}")
    allPhases.add(phase)
}
println(allPhases)

验证输出

执行上述代码后,每个phase的directories都会对应各自的id值:

[
    [type:a, directories:[[dir:a/b/c, command:apply/1]], id:1],
    [type:a, directories:[[dir:a/b/c, command:apply/2]], id:2],
    [type:a, directories:[[dir:a/b/c, command:apply/3]], id:3]
]

内容的提问来源于stack exchange,提问作者TomNash

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:00:30