跃然一笑
在不了解有关您的数据/模式的安全假设的更多详细信息的情况下,很难推荐完整的解决方案,但我可以尝试一下您在此处拥有的内容。将您的概念从接口稍微限制为代表您的节点的结构可能会使这里的事情变得更容易一些。type ConfigNode struct { Type string Properties map[string]string Connected []*ConfigNode}func (n *ConfigNode) PatchProperties(patch *ConfigNode) { for k, v := range patch.Properties { n.Properties[k] = v }}func (n ConfigNode) ShallowClone() ConfigNode { clone := ConfigNode{ Type: n.Type, Properties: make(map[string]string), Connected: make([]*ConfigNode, 0), } clone.PatchProperties(&n) return clone}func (n *ConfigNode) PrintTree() string { builder := strings.Builder{} n.appendToTreePrint(&builder, 0) return builder.String()}func (n *ConfigNode) appendToTreePrint(builder *strings.Builder, depth int) { isRoot := builder == nil tab := strings.Repeat("\t", depth) if isRoot { builder = &strings.Builder{} } builder.WriteString(tab) builder.WriteString(n.Type) builder.WriteRune('\n') for k, v := range n.Properties { builder.WriteString(fmt.Sprintf("%s - %s => %s\n", tab, k, v)) } for _, c := range n.Connected { c.appendToTreePrint(builder, depth+1) }}func mergeNodes(base []*ConfigNode, patch []*ConfigNode) []*ConfigNode { merged := make([]*ConfigNode, 0) if patch == nil { // No patch is being applied, just deep copy the base nodes. for _, node := range base { clone := node.ShallowClone() clone.Connected = mergeNodes(clone.Connected, nil) merged = append(merged, &clone) } return merged } baseTypes := make(map[string]*ConfigNode) patchTypes := make(map[string]*ConfigNode) // Key the nodes by their Type so we can match them. for _, node := range base { baseTypes[node.Type] = node } for _, node := range patch { patchTypes[node.Type] = node } for k, v := range baseTypes { mergedNode := v.ShallowClone() if patchNode, ok := patchTypes[k]; ok { // A patch node was found with the Type matching the base, combine the two. mergedNode.PatchProperties(patchNode) // Remove the patch node so we don't iterate through it later. delete(patchTypes, k) // Recurse in and merge child nodes. mergedNode.Connected = mergeNodes(v.Connected, patchNode.Connected) } else { // There is no patch so we can just deep copy the children. mergedNode.Connected = mergeNodes(v.Connected, nil) } merged = append(merged, &mergedNode) } // Any unmatched patch nodes can be deep copied into the output. for _, v := range patchTypes { mergedNode := v.ShallowClone() mergedNode.Connected = mergeNodes(v.Connected, nil) merged = append(merged, &mergedNode) } return merged}func printConfig(name string, config []*ConfigNode) { fmt.Println(name + ":") for _, v := range config { fmt.Println(v.PrintTree()) }}func initTestNodes() (base []*ConfigNode, patch []*ConfigNode) { var node1Base ConfigNode var node2Base ConfigNode var node3Base ConfigNode var node1Patch ConfigNode var node3Patch ConfigNode var node4Patch ConfigNode node1Base = ConfigNode{ Type: "func1", Properties: map[string]string{ "params1": "orig1", "params2": "orig1", }, Connected: []*ConfigNode{&node2Base}, } node2Base = ConfigNode{ Type: "func2", Properties: map[string]string{ "params1": "orig2", "params2": "orig2", }, Connected: []*ConfigNode{&node3Base}, } node3Base = ConfigNode{ Type: "func3", Properties: map[string]string{ "params1": "orig3", "params2": "orig3", }, Connected: []*ConfigNode{}, } node1Patch = ConfigNode{ Type: "func1", Properties: map[string]string{ "params1": "up1", }, Connected: []*ConfigNode{&node4Patch}, } node3Patch = ConfigNode{ Type: "func3", Properties: map[string]string{ "params1": "up3", }, Connected: []*ConfigNode{}, } node4Patch = ConfigNode{ Type: "func4", Properties: map[string]string{ "params1": "up4", }, Connected: []*ConfigNode{&node3Patch}, } return []*ConfigNode{&node1Base}, []*ConfigNode{&node1Patch}}func main() { baseConfig, patchConfig := initTestNodes() merged := mergeNodes(baseConfig, patchConfig) printConfig("Base Config", baseConfig) printConfig("Patch Config", patchConfig) printConfig("Merged Config", merged)}