如何有效地更新两个结构的值 [英] How to update value of two struct efficiently

查看:46
本文介绍了如何有效地更新两个结构的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码来解析YAML文件,并且需要匹配一个结构external中的值并更新internal结构的type属性.

I have the following code which parses YAML files and needs to match values from one struct external and update the internal struct's type property.

例如,这是yaml文件(为简单起见,将其翻译为bin)和正确解析的内容

For example, this is the yaml file(translated to bin for simplicity) and content which is parsed correctly

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以上的结构 当我需要修改 internal_config中的type值时,这些更改是,这里是从app1GCPapp2amazon

At the end what I need to do is to get the internal yaml file to be changed to the struct above internal_config_after_changes The changes are when the type=app-type I need to modify the type value in the internal_config, here from app1 to GCP and app2 to amazon

问题出在第二个循环上,我应该用它来迭代external_config和匹配的值,我不确定如何用有效的方式将它们结合起来……

The problem is with the second loop which I should use to iterate on the external_config and the matching values, I'm not sure how to combine them both with efficient way...

推荐答案

Golang有关映射到地图和切片的指针的常见问题解答:

Golang FAQ described regarding pointers to maps and slice:

映射和切片值的行为类似于指针:它们是描述符, 包含指向基础地图或切片数据的指针.复制地图或 切片值不会复制其指向的数据.复制界面 值复制存储在接口值中的事物的副本.如果 接口值包含一个结构,复制接口值使 结构的副本.如果接口值包含指针,则复制 接口值将创建指针的副本,但同样不会 它指向的数据.

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内部的模型切片时,您实际上是在创建[]Models切片的副本,其值.由于该原因,Type不会更改原始struct的值.

On iterating through the slice of model inside ConvertType you are actually creating a copy of []Models slice whose value.Type is not changing the value of original struct due that reason.

for _, module := range int_cfg.models{}

以上代码段正在创建int_cfg.models{}的副本.

Above code snippet is creating a copy of int_cfg.models{}.

索引切片模型以指向切片模型的确切基础数组,以将值更改为:

Index the slice model to point to the exact underlying array of slice Model to change the value as:

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
}

如果您检查以上代码段,您还将认识到我已经更改了结构.

If you check above code snippet, you will also recognize that I have changed the struct.

type InternalModel struct {
    models []Model2 `yaml:"models"`
}

首字母大写以使其可导出为:

to first letter uppercase to make it exportable as:

type InternalModel struct {
    Models []Model2 `yaml:"models"`
}

由于结构InternalModel是不可导出的字段,因此model无法解析提供的internal_config yaml,从而导致在取消编组yaml后导致空的[] slice数据.

Because of the struct InternalModel is unexportable field model was unable to parse the provided internal_config yaml which leads to empty []slice data after unmarshal yaml.

我注意到的另一件事是您将字节再次转换为字节.没必要.

One more thing that I have noticed is you are converting bytes into bytes again. There is no need for that.

err := yaml.Unmarshal([]byte(internal_config), &internalConfiglYaml)

所以我将其更改为:

err := yaml.Unmarshal(internal_config, &internalConfiglYaml)

因为在全局变量中已经使用[]byteinternal_config声明为字节.

Since internal_config is already declared as byte using []byte in global variable.

这篇关于如何有效地更新两个结构的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆