templates - Go 模板 : Are Nested Ranges Possible?

标签 templates go

这个看似简单,却让我发疯。

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

例子:

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

在模板中:

{{range .foos}}
  <div>Foo {{.Name}}</div>
  <div>
    {{range ..bars}}
      <div>Bar {{.Name}} <input type="text" name="ids_{{..Id}}_{{.Id}}" /></div>
    {{end}}
  </div>
{{end}}

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

问题是似乎不可能:

  1. 从 foos 范围范围内访问栏
  2. 在 bar 的范围内访问 Foo 的 ID

我有一个临时的解决方法,方法是在两个结构中放置一堆冗余字段,但这对我来说似乎很丑陋,违反了 DRY,而且总的来说感觉很不对。

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

最佳答案

是的。我觉得好像没有找到解决方案来自没有足够仔细地阅读 text/template 包。如果您使用的是 html/template,则语法是相同的(它们会告诉您阅读 text/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())
}

注意:您可能可以采取一些措施不将文件加载到中间缓冲区(使用 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}}

这个故事的两个寓意是
a) 明智地在模板中使用变量,它们是有益的
b) 模板中的 range 也可以设置变量,不需要单独依赖 $.

关于templates - Go 模板 : Are Nested Ranges Possible?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17509420/

相关文章:

c++ - 未为使用默认模板参数声明的别名模板指定模板参数时出错

c++ - 检查类是否继承自模板的任何模板实例化

django - django 模板中基于日期的通用 View 的 URL?

shell - 如何在 golang 中获取 gcloud 命令的结果?

go - 在 Go 中命名接收器变量 'self' 是误导还是好的做法?

go - 如何从 Golang 中的字符串周围删除引号

xcode - 这些演示者的代码模板工作流程是什么?

c++ - 我的 std::hash for std::tuples...有什么改进吗?

go - 如何初始化 Go 结构中的特定字段

json - 解析POST请求中发送的json正文数组并打印