[英]Golang merge deeply two maps
I'm trying to deep copy of two yaml, trying to simulate the behaviour that use helm when you pass multiple values during an installation.我正在尝试对两个 yaml 进行深度复制,试图模拟在安装过程中传递多个值时使用helm的行为。 Because of a project restriction, I'm getting the values from strings and not directly form yamls.
由于项目限制,我从字符串中获取值,而不是直接形成 yaml。 The problem is that the copy is not done as I expect.
问题是复制没有按照我的预期完成。
I add an example:我添加一个例子:
value1 :值 1 :
test:
somekey: 1
otherkey: 2
othertest:
somekey: 3
value2 :值 2 :
test:
somekey: NEWVALUE1
NEWKEY: NEWVALUE2
EXPECTED OUTPUT :预计 OUTPUT :
test:
somekey: NEWVALUE1
otherkey: 2
NEWKEY: NEWVALUE2
othertest:
somekey: 3
RESULT :结果:
othertest:
somekey: 3
test:
NEWKEY: NEWVALUE2
somekey: NEWVALUE1
So as you can see in the example, it is overwritting all the test
map, when I would like to merge both test
maps.因此,正如您在示例中看到的,当我想合并两个
test
图时,它覆盖了所有test
map。
Here I add the code I'm using在这里我添加我正在使用的代码
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
}
I think the error is that I'm generating incorrectly the map from the string var resultValues map[string]interface{}
, but I didn't find the way to convert the string to a map我认为错误是我从字符串
var resultValues map[string]interface{}
错误地生成了 map ,但我没有找到将字符串转换为 map 的方法
Use map[interface{}]interface{}
instead of map[string]interface{}
.使用
map[interface{}]interface{}
而不是map[string]interface{}
。 You could have a deeper look at yaml.Unmarshal .您可以更深入地了解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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.