dongxie8856 2018-10-12 09:42
浏览 180
已采纳

在GO模板中对结构使用范围

I parse the struct from values.yaml and want to use it in template.yaml

Here is my values.yaml file:

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

And here is my template.yaml (NOT VALID CODE):

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

Which gives me error:

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

Here is my .go code:

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)
}

How can I iterate over .Services in template.yaml correctly? I found only option with {{- range $key, $value := .Services}} but it doesn't work.

  • 写回答

1条回答 默认 最新

  • dongshang5862 2018-10-12 09:52
    关注

    You can't range over fields of a struct, as you experienced. You can only range over slices, arrays, maps and channels.

    Using a map

    So easiest would be to pass that: a map. You can directly unmarshal a YAML into a map or the empty interface:

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

    Changing a little the format of your template (note the .services):

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

    With these, it works and output is:

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

    Using a slice

    If you want to keep using your Services model, another option would be to prepare and pass a slice of the fields manually:

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

    And then the template:

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

    And then the output:

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

    Using a slice and reflection

    If you want it to remain "dynamic" (meaning you don't have to enumerate fields manually), you can create a helper function which does that using reflection. For an example how to do that, see Get all fields from an interface and Iterate through the fields of a struct in Go.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值