loops - 如何有效地更新两个结构的值

标签 loops go recursion struct yaml

我有以下解析 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_config,这里从app1GCP,从app2amazon

问题出在第二个循环上,我应该用它来迭代 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/

相关文章:

java - 计算Java中二叉树中的节点数

loops - 在 SAS `X` 命令中,如何传递回车符?

go env 显示 GOPATH 不匹配

java - 了解嵌套循环和类

windows - GoSublime - 可以在代码完成弹出窗口旁边显示文档吗?

pointers - golang 异常规则 "interface pointer can' t 实现接口(interface)”

javascript - JS中递归调用函数的次数

javascript - 如何使这个同步递归函数异步

c++ - 迭代集合而不首先生成集合

javascript - return 会停止循环吗?