【问题标题】:Syntax for creating struct map key in Go HTML template在 Go HTML 模板中创建结构映射键的语法
【发布时间】:2017-08-10 10:36:19
【问题描述】:

我正在编写一个简单的 Go 程序来显示每个环境已部署服务版本的 HTML 表格。我的程序包含以下结构:

type versionKey struct {
    Environment string
    Service     string
}

type templateData struct {
    Environments []string
    Services     []string
    Versions     map[versionKey]string
}

如您所见,Versions 映射使用versionKey 作为字符串值的键,例如"1.0.0".

我将 templateData 结构传递给 HTML 模板,并在其 EnvironmentsServices 切片上构建 HTML 表。问题是我需要为环境和服务的任何给定交集构造一个versionKey,以便我可以使用它从Versions 映射中查找版本并将该值输出到表格单元格中。

在模板中,我有范围内可用的 $environment$service 变量,但我无法使用 Go 模板语法来创建 versionKey 结构。

这是省略标记的模板代码:

{{$environments := .Environments}}
{{$services := .Services}}
{{$versions := .Versions}}

{{range $service := $services}}
  ...
  {{range $environment := $environments}}
    ...
    {{index $versions ...? }} // How to create versionKey struct map key here?
    ...
  {{end}}
  ...
{{end}}

【问题讨论】:

    标签: go go-templates


    【解决方案1】:

    您不能只使用模板代码。你需要执行 Go 代码的某种支持才能做到这一点。根据设计理念,模板不应包含复杂的逻辑。您可能会争论这是否复杂,但模板语法不支持这一点。

    最简单的解决方案是将Version() 方法添加到templateData 结构中,这将简单地返回给定环境和服务的版本:

    func (t *templateData) Version(environment, service string) string {
        return t.Versions[versionKey{
            Environment: environment,
            Service:     service,
        }]
    }
    

    从模板中使用它:

    {{range $service := $services -}}
      {{range $environment := $environments}}
        {{$environment}} - {{$service}} version: {{$.Version $environment $service}}
      {{end}}
    {{end}}
    

    测试它:

    t := template.Must(template.New("").Parse(templ))
    td := &templateData{
        Environments: []string{"EnvA", "EnvB"},
        Services:     []string{"ServA", "ServB"},
        Versions: map[versionKey]string{
            {"EnvA", "ServA"}: "1.0.0",
            {"EnvA", "ServB"}: "1.0.1",
            {"EnvB", "ServA"}: "1.0.2",
        },
    }
    if err := t.Execute(os.Stdout, td); err != nil {
        panic(err)
    }
    

    输出(在Go Playground上试试):

    EnvA - ServA version: 1.0.0
    
    EnvB - ServA version: 1.0.2
    
    
    EnvA - ServB version: 1.0.1
    
    EnvB - ServB version: 
    

    替代品

    除了templateData.Version() 方法,您还可以轻松地注册一个函数,该函数可以从给定的环境和服务创建并返回versionKey 类型的值。有关详细信息,请参阅Template.Funcs()。虽然这会更复杂,但更灵活,因为它可以在其他地方重用。在此处查看示例:Golang templates (and passing funcs to template)。一个轻微的变化是将函数值作为任何其他模板数据传递,而不是将其注册为可以调用的命名函数。

    另一种选择是将您的 Versions 字段“转换”为地图地图,例如:

    Versions map[string]map[string]string
    

    首先可以按环境索引,然后按服务索引,在模板中您可以通过 2 个{{index}} 操作来实现。不过,您必须检查第一个索引是否产生任何结果。

    【讨论】:

    • 一个极好的答案,非常感谢。出于兴趣,你为什么使用templateData 的指针?
    • @JohnTopley 两者(指针和非指针接收器)都可以在这个简单的例子中工作。我出于纯粹的习惯使用指针接收器,如果示例演变为更复杂的示例,其中方法还需要改变/修改接收器,我不必返回并将接收器更改为指针接收器。
    猜你喜欢
    • 2018-10-18
    • 2013-08-07
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多