在 GO 模板中使用 range over struct

Use range over struct in GO templates

我从 values.yaml 解析结构体并想在 template.yaml

中使用它

这是我的 values.yaml 文件:

services:
  app:
    image: matryoshka/app
    replicaCount: 1
  cron:
    image: matryoshka/cron
    replicaCount: 1

这是我的 template.yaml(无效代码):

{{- range $key, $value := .Services}}
    {{$key}}{{$value}}
{{- end}}

这给我错误:

panic: template: template.yaml:1:26: executing "template.yaml" at <.Services>: range can't iterate over {{atryoshka/app 1} {matryoshka/cron 1}}

这是我的 .go 代码:

package main

import (
    "html/template"
    "io/ioutil"
    "os"
    "path/filepath"

    "gopkg.in/yaml.v2"
)

type Values struct {
    Services struct {
        App struct {
            Image        string `yaml:"image"`
            ReplicaCount string `yaml:"replicaCount"`
        } `yaml:"app"`
        Cron struct {
            Image        string `yaml:"image"`
            ReplicaCount string `yaml:"replicaCount"`
        } `yaml:"cron"`
    }
}

func parseValues() Values {

    var values Values
    filename, _ := filepath.Abs("./values.yaml")
    yamlFile, err := ioutil.ReadFile(filename)

    err = yaml.Unmarshal(yamlFile, &values)
    if err != nil {
        panic(err)
    }

    return values

}
func insertValues(class Values) {
    paths := []string{"template.yaml"}
    t, err := template.New(paths[0]).ParseFiles(paths...)
    if err != nil {
        panic(err)
    }
    err = t.Execute(os.Stdout, class)
    if err != nil {
        panic(err)
    }
}

func main() {
    values := parseValues()
    insertValues(values)
}

如何正确地在 template.yaml 中迭代 .Services?我只找到 {{- range $key, $value := .Services}} 的选项,但它不起作用。

您不能像您所经历的那样遍历结构的字段。您只能对切片、数组、映射和通道进行范围。

使用地图

最简单的方法就是通过:一张地图。您可以直接将 YAML 解组为映射或空接口:

func parseValues() interface{} {
    var values interface{}
    // ...rest is unchanged
}

func insertValues(class interface{}) {
    // ...unchanged
}

稍微更改模板的格式(注意 .services):

{{- range $key, $value := .services}}
{{$key}} {{$value}}
{{- end}}

有了这些,它就可以工作,输出是:

app map[replicaCount:1 image:matryoshka/app]
cron map[image:matryoshka/cron replicaCount:1]

使用切片

如果您想继续使用您的 Services 模型,另一种选择是手动准备和传递一部分字段:

insertValues([]interface{}{values.Services.App, values.Services.Cron})

然后是模板:

{{- range $key, $value := .}}
{{$key}} {{$value}}
{{- end}}

然后输出:

0 {matryoshka/app 1}
1 {matryoshka/cron 1}

使用切片和反射

如果您希望它保持 "dynamic"(意味着您不必手动枚举字段),您可以创建一个辅助函数,它使用反射来完成。有关如何执行此操作的示例,请参阅 and Iterate through the fields of a struct in Go.