如何有效地更新两个结构的值 [英] How to update value of two struct efficiently
问题描述
我有以下代码来解析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
值时,这些更改是,这里是从app1
到GCP
和app2
到amazon
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)
因为在全局变量中已经使用[]byte
将internal_config
声明为字节.
Since internal_config
is already declared as byte using []byte
in global variable.
这篇关于如何有效地更新两个结构的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!