转到模板:嵌套范围可能吗?

hap*_*oid 20 templates go

这个看似简单,但它让我疯了.

如何在golang模板中的嵌套范围内引用范围更高的struct元素?

例:

type Foo struct {
  Id string
  Name string
}

type Bar struct {
  Id string
  Name string
}

var foos []Foo
var bars []Bar

// logic to populate both foos and bars
Run Code Online (Sandbox Code Playgroud)

在模板中:

{{range .foos}}
  <div>Foo {{.Name}}</div>
  <div>
    {{range ..bars}}
      <div>Bar {{.Name}} <input type="text" name="ids_{{..Id}}_{{.Id}}" /></div>
    {{end}}
  </div>
{{end}}
Run Code Online (Sandbox Code Playgroud)

显然..bars和..Id不起作用,但希望我的意图很明确.我想迭代Foo和Bar的所有组合,并生成一个表单元素,其名称由Foo的Id和Bar的Id构建.

问题是似乎不可能:

  1. 来自foos范围范围内的访问条
  2. 从条形范围内访问Foo的Id

我通过在两个结构中放置一堆冗余字段来对此进行临时解决,但这对我来说似乎非常难看,违反了DRY,并且总体上感觉非常错误.

golang模板有什么方法可以做我想做的事情吗?

twm*_*wmb 29

是.我觉得似乎没有找到解决方案来自不仔细阅读text/template包.如果您正在使用html/template,语法是相同的(它们告诉您阅读文本/模板;)).这是一个完整的工作解决方案,可以满足您的需求.

去文件:

package main

import (
    "bytes"
    "io/ioutil"
    "os"
    "strconv"
    "text/template"
)

type Foo struct {
    Id   string
    Name string
}

type Bar struct {
    Id   string
    Name string
}

var foos []Foo
var bars []Bar

func main() {
    foos = make([]Foo, 10)
    bars = make([]Bar, 10)

    for i := 0; i < 10; i++ {
        foos[i] = Foo{strconv.Itoa(i), strconv.Itoa(i)} // just random strings
        bars[i] = Bar{strconv.Itoa(10 * i), strconv.Itoa(10 * i)}
    }

    tmpl, err := ioutil.ReadFile("so.tmpl")
    if err != nil {
        panic(err)
    }

    buffer := bytes.NewBuffer(make([]byte, 0, len(tmpl)))

    output := template.Must(template.New("FUBAR").Parse(string(tmpl)))
    output.Execute(buffer, struct {
        FooSlice []Foo
        BarSlice []Bar
    }{
        FooSlice: foos,
        BarSlice: bars,
    })

    outfile, err := os.Create("output.html")
    if err != nil {
        panic(err)
    }
    defer outfile.Close()
    outfile.Write(buffer.Bytes())
}
Run Code Online (Sandbox Code Playgroud)

注意:您可以做一些事情来不将文件加载到中间缓冲区(使用ParseFiles),我只是复制并粘贴了我为我的一个项目编写的一些代码.

模板文件:

{{ $foos := .FooSlice }}
{{ $bars := .BarSlice }}

{{range $foo := $foos }}
  <div>Foo {{$foo.Name}}</div>
  <div>
    {{range $bar := $bars}}
      <div>Bar {{$bar.Name}} <input type="text" name="ids_{{$foo.Id}}_{{$bar.Id}}" /></div>
    {{end}}
  </div>
{{end}}
Run Code Online (Sandbox Code Playgroud)

这个故事的两个道德是:
a)明智地使用模板中的变量,它们是有益的
b)模板中的范围也可以设置变量,你不需要单独依赖$.