我有以下解析 YAML 文件的代码,需要匹配来自一个结构 external
的值并更新 internal
结构的 type
属性。
例如,这是正确解析的 yaml 文件(为简单起见翻译为 bin)和内容
package main
import (
"fmt"
"gopkg.in/yaml.v2"
"log"
)
//internal config model for parsing
type InternalModel struct {
models []Model2 `yaml:"models"`
}
type Model2 struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Target string `yaml:"target"`
}
var internal_config = []byte(`
models:
- name: myapp
type: app1
target: ./
- name: myapp2
type: app2
target: ./
`)
type ExternalConfig struct {
Landscape Zone `yaml:"Landscape"`
}
type Zone struct {
Zone string `yaml:"zone"`
Models []Model `yaml:"models"`
}
type Model struct {
AppType string `yaml:"app-type"`
ServiceType string `yaml:"service-type"`
}
var external_config = []byte(`
Landscape:
zone: zone1
models:
- app-type: app1
service-type: GCP
- app-type: app2
service-type: AMAZON
zone: zone2
models:
- app-type: app3
service-type: AZURE
- app-type: app4Í
service-type: HEROKU
`)
func main() {
// This is the internal config which needs updated
internalConfiglYaml := InternalModel{}
err := yaml.Unmarshal([]byte(internal_config), &internalConfiglYaml)
if err != nil {
log.Fatalf("error in model internalConfiglYaml: %v", err)
}
//fmt.Printf("%+v\n", internalConfiglYaml)
//--------------------------Second config file-----------------------//
//This is the external config yaml
extConfigYaml := ExternalConfig{}
err = yaml.Unmarshal([]byte(external_config), &extConfigYaml)
if err != nil {
log.Fatalf("error in model extConfigYaml: %v", err)
}
fmt.Printf("%+v\n", extConfigYaml)
landscape := "zone1"
modifiedConfig := ConvertTypes(internalConfiglYaml, extConfigYaml, landscape)
fmt.Printf("%+v\n", modifiedConfig)
}
func ConvertTypes(int_cfg InternalModel, ext_config ExternalConfig, landscape string) (out_cfg InternalModel) {
for _, module := range int_cfg.models {
switch module.Type {
case "app1":
//here I hard-coded the value "GCP" but it should come from the yaml struct after parsing
module.Type = "GCP" // should be something like ext_config.models.service-type when the key in the struct
case "app2":
//here I hard-coded the value "AMAZON" but it should come from the yaml struct after parsing
module.Type = "AMAZON"
}
}
return int_cfg
}
//At the end what I need to do is to get the internal yaml file to be changed to the following struct
//The changes are when the type=app-type I need to modify the type in the internal config, here its GCP and ruby
//internal_config_after_changes := []byte(`
//
//
//models:
// - name: myapp
// type: GCP
// target: ./
//
// - name: myapp2
// type: AMAZON
// target: ./
//
//
//`)
最后我需要做的是将内部yaml文件更改为internal_config_after_changes
上面的结构
变化是当type=app-type
我需要修改中的
,这里从type
值internal_configapp1
到GCP
,从app2
到amazon
问题出在第二个循环上,我应该用它来迭代 external_config
和匹配值,我不确定如何以有效的方式将它们结合起来...
最佳答案
关于映射和 slice 指针的 Golang 常见问题解答:
Map and slice values behave like pointers: they are descriptors that contain pointers to the underlying map or slice data. Copying a map or slice value doesn't copy the data it points to. Copying an interface value makes a copy of the thing stored in the interface value. If the interface value holds a struct, copying the interface value makes a copy of the struct. If the interface value holds a pointer, copying the interface value makes a copy of the pointer, but again not the data it points to.
在遍历 ConvertType
中的模型 slice 时,您实际上是在创建 []Models
slice 的副本,其 value.Type 不会更改原始结构的值,因为那个原因。
for _, module := range int_cfg.models{}
以上代码片段正在创建 int_cfg.models{}
的副本。
索引 slice 模型以指向 slice 模型的确切底层数组以将值更改为:
package main
import (
"fmt"
"log"
"strings"
"gopkg.in/yaml.v2"
)
//internal config model for parsing
type InternalModel struct {
Models []Model2 `yaml:"models"`
}
type Model2 struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Target string `yaml:"target"`
}
var internal_config = []byte(`
models:
- name: myapp
type: app1
target: ./
- name: myapp2
type: app2
target: ./
`)
type ExternalConfig struct {
Landscape []Zone `yaml:"Landscape"`
}
type Zone struct {
Zone string `yaml:"zone"`
Models []Model `yaml:"models"`
}
type Model struct {
AppType string `yaml:"app-type"`
ServiceType string `yaml:"service-type"`
}
var external_config = []byte(`
Landscape:
- zone: zone1
models:
- app-type: app1
service-type: GCP
- app-type: app2
service-type: AMAZON
- zone: zone2
models:
- app-type: app3
service-type: AZURE
- app-type: app4Í
service-type: HEROKU
`)
func main() {
//This is the internal config which needs to be update
internalConfiglYaml := InternalModel{}
err := yaml.Unmarshal(internal_config, &internalConfiglYaml)
if err != nil {
log.Fatalf("error in model internalConfiglYaml: %v", err)
}
fmt.Printf("%+v\n", internalConfiglYaml)
//--------------------------Second config file-----------------------//
//This is the external config yaml
extConfigYaml := ExternalConfig{}
// var response interface{}
err = yaml.Unmarshal(external_config, &extConfigYaml)
if err != nil {
log.Fatalf("error in model extConfigYaml: %v", err)
}
fmt.Printf("%+v\n", extConfigYaml)
landscape := "zone1"
modifiedConfig := ConvertTypes(&internalConfiglYaml, extConfigYaml, landscape)
fmt.Printf("%+v\n", modifiedConfig)
}
// ConvertTypes for changing the intConfig struct types
func ConvertTypes(int_cfg *InternalModel, ext_config ExternalConfig, landscape string) (out_cfg *InternalModel) {
for _, module := range ext_config.Landscape {
if module.Zone == landscape {
for i, value := range module.Models {
switch strings.Compare(value.AppType, int_cfg.Models[i].Type) {
case 0:
//here I hard-coded the value "GCP" but it should come from the yaml struct after parsing
int_cfg.Models[i].Type = value.ServiceType // should be something like ext_config.models.service-type when the key in the struct
default:
}
}
}
}
return int_cfg
}
如果您检查上面的代码片段,您还会发现我更改了结构。
type InternalModel struct {
models []Model2 `yaml:"models"`
}
首字母大写,使其可导出为:
type InternalModel struct {
Models []Model2 `yaml:"models"`
}
由于结构 InternalModel
是不可导出字段 model
无法解析提供的 internal_config
yaml,这导致空 []slice 数据之后解码 yaml。
我注意到的另一件事是您再次将字节转换为字节。没有必要。
err := yaml.Unmarshal([]byte(internal_config), &internalConfiglYaml)
所以我把它改成了:
err := yaml.Unmarshal(internal_config, &internalConfiglYaml)
因为 internal_config
已经在全局变量中使用 []byte
声明为 byte。
关于loops - 如何有效地更新两个结构的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51803219/