【问题标题】:Golang merge deeply two mapsGolang 深度合并两张地图
【发布时间】:2020-11-07 05:22:24
【问题描述】:

我正在尝试对两个 yaml 进行深度复制,试图模拟在安装期间传递多个值时使用 helm 的行为。 由于项目限制,我从字符串中获取值,而不是直接形成 yaml。 问题是副本没有按我的预期完成。

我添加一个例子:

值1

test:
  somekey: 1
  otherkey: 2
othertest:
  somekey: 3

值2

test:
  somekey: NEWVALUE1
  NEWKEY: NEWVALUE2

预期输出

test:
  somekey: NEWVALUE1
  otherkey: 2
  NEWKEY: NEWVALUE2
othertest:
  somekey: 3

结果

othertest:
  somekey: 3
test:
  NEWKEY: NEWVALUE2
  somekey: NEWVALUE1

正如您在示例中看到的那样,当我想合并两个 test 映射时,它会覆盖所有 test 映射。

我在这里添加我正在使用的代码

package main

import (
    "github.com/prometheus/common/log"
    "gopkg.in/yaml.v2"
)

func main() {
    value1 := "test:\n  somekey: 1\n  otherkey: 2\nothertest:\n  somekey: 3"
    value2 := "test:\n  somekey: NEWVALUE1\n  NEWKEY: NEWVALUE2"
    values := []string{value1, value2}
    result, err := getValuesFromString(values)
    if err != nil {
        log.Info(err)
    }

    //expecting: test:\n  somekey: NEWVALUE1\n  otherkey: 2\n  NEWKEY: NEWVALUE2\nothertest:\n  somekey: 3
    //getting: othertest:\n  somekey: 3\ntest:\n  NEWKEY: NEWVALUE2\n  somekey: NEWVALUE1\n
    log.Info("FINAL VALUES: " + result)
}

func getValuesFromString(values []string) (string, error) {

    var resultValues map[string]interface{}
    var bs []byte
    for _, value := range values {
        log.Info(values)
        var override map[string]interface{}
        bs = []byte(value)

        if err := yaml.Unmarshal(bs, &override); err != nil {
            log.Info(err)
            continue
        }

        //check if is nil. This will only happen for the first value
        if resultValues == nil {
            resultValues = override
        } else {
            resultValues = mergeMaps(resultValues, override)
        }
    }

    bs, err := yaml.Marshal(resultValues)
    if err != nil {
        log.Info(err)
        return "", err
    }

    return string(bs), nil
}

func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
    out := make(map[string]interface{}, len(a))
    for k, v := range a {
        out[k] = v
    }
    for k, v := range b {
        if v, ok := v.(map[string]interface{}); ok {
            if bv, ok := out[k]; ok {
                if bv, ok := bv.(map[string]interface{}); ok {
                    out[k] = mergeMaps(bv, v)
                    continue
                }
            }
        }
        out[k] = v
    }
    return out
}

我认为错误是我从字符串var resultValues map[string]interface{} 错误地生成了地图,但是我没有找到将字符串转换为地图的方法

【问题讨论】:

  • NEWVALUE2x 是不是搞错了?
  • 是的。编辑。 NEWKEY: NEWVALUE2
  • 我在go 中发现了很多问题,这很清楚,也表明一些努力总是被否决。:)

标签: dictionary go merge yaml kubernetes-helm


【解决方案1】:

使用map[interface{}]interface{} 而不是map[string]interface{}。您可以深入了解yaml.Unmarshal

func mergeMaps(a, b map[interface{}]interface{}) map[interface{}]interface{} {
    out := make(map[interface{}]interface{}, len(a))
    for k, v := range a {
        out[k] = v
    }
    for k, v := range b {
        // If you use map[string]interface{}, ok is always false here.
        // Because yaml.Unmarshal will give you map[interface{}]interface{}.
        if v, ok := v.(map[interface{}]interface{}); ok {
            if bv, ok := out[k]; ok {
                if bv, ok := bv.(map[interface{}]interface{}); ok {
                    out[k] = mergeMaps(bv, v)
                    continue
                }
            }
        }
        out[k] = v
    }
    return out
}

【讨论】:

  • 我可以将interface{} 视为 GO 中的Generic 吗?
  • 更类似于void*,甚至不接近泛型/模板
猜你喜欢
  • 1970-01-01
  • 2017-12-25
  • 1970-01-01
  • 2019-11-09
  • 2023-03-06
  • 2018-10-23
  • 2015-05-05
  • 2021-08-18
  • 1970-01-01
相关资源
最近更新 更多