我有以下代码,该代码分析YAML文件,并且需要匹配一个结构的值external并更新该internal结构的type属性。
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_config,这里是从app1to GCP和app2toamazon
internal_config_after_changes
type=app- type
internal_config
app1
GCP
app2
amazon
问题在于第二个循环,我应该使用它来迭代external_config和匹配的值,我不确定如何以有效的方式将它们组合在一起。
external_config
Golang常见问题解答介绍了有关地图和切片的指针:
映射和切片值的行为类似于指针:它们是包含指向基础映射或切片数据的指针的描述符。复制地图或切片值不会复制其指向的数据。复制接口值将复制存储在接口值中的事物。如果接口值包含一个结构,则复制接口值将复制该结构。如果接口值包含一个指针,则复制接口值将复制该指针,但不会复制它指向的数据。
在遍历内部模型切片时,ConvertType实际上是在创建[]Models其值的切片副本。由于该原因,Type不会更改原始结构的值。
ConvertType
[]Models
for _, module := range int_cfg.models{}
上面的代码段正在创建的副本int_cfg.models{}。
int_cfg.models{}
索引切片模型以指向切片模型的确切基础数组,以将值更改为:
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"` }
由于struct InternalModelis unexportable,因此字段model无法解析提供的internal_configyaml,从而导致在解组yaml后导致空的[] slice数据。
InternalModel
model
我注意到的另一件事是您再次将字节转换为字节。没有必要。
err := yaml.Unmarshal([]byte(internal_config), &internalConfiglYaml)
所以我将其更改为:
err := yaml.Unmarshal(internal_config, &internalConfiglYaml)
因为internal_config已经[]byte在全局变量中使用字节声明。
[]byte