比较 Go 模板中的两个变量

Posted

技术标签:

【中文标题】比较 Go 模板中的两个变量【英文标题】:Compare two variables inside Go template 【发布时间】:2017-11-27 19:21:46 【问题描述】:

在我传递给我的模板的数据中,我有两个变量 TypeRes.Type 我想比较以便为我的选择字段预选一个选项。

为了说明我的问题,我创建了这个简化版本:

package main

import (
    "bufio"
    "bytes"
    "html/template"
    "log"
)

type Result struct Type string 

func main() 
    types := map[string]string
        "FindAllString":      "FindAllString",
        "FindString":         "FindString",
        "FindStringSubmatch": "FindStringSubmatch",
    
    res := &ResultType: "findAllString"

    templateString := `
    <select name="type">
         range $key,$value := .Types 
             if eq $key .Res.Type 
                <option value="$key" selected>$value</option>
             else 
                <option value="$key">$value</option>
             end 
         end 
    </select>`
    t, err := template.New("index").Parse(templateString)
    if err != nil 
        panic(err)
    
    var b bytes.Buffer
    writer := bufio.NewWriter(&b)
    err = t.Execute(writer, struct 
        Types map[string]string
        Res   *Result
    types, res)
    if err != nil 
        panic(err)
    
    writer.Flush()
    log.Println(b.String())

它应该选择"FindAllString" 选项但它只会产生错误

panic: template: index:4:21: executing "index" at <.Res.Type>: can't evaluate field Res in type string

goroutine 1 [running]:
panic(0x53f6e0, 0xc4200144c0)
    /usr/local/go/src/runtime/panic.go:500 +0x1a1
main.main()
    /home/tobias/ngo/src/github.com/gamingcoder/tmp/main.go:41 +0x523
exit status 2

当我只比较两个普通字符串时,它可以工作,但我想知道是否有一种惯用的方法来做到这一点。我已经看到你可以在模板中添加一个函数,但我觉得必须有一个更简单的方法。

【问题讨论】:

【参考方案1】:

问题在于range 操作会更改(设置)点(.),即使您在您的情况下使用循环变量($key$value)。在range 中,点被设置为当前元素。

range 里面你写:

 if eq $key .Res.Type 

由于循环中的值是 string 值,.Res.Type 是错误的,因为没有 Res 字段或 string 值的方法(当前元素由点 . 表示)。

使用$ 符号不是指循环值,而是指传递给模板执行的参数:

 if eq $key $.Res.Type 

这会起作用,但不会给你想要的输出,因为你有一个错字:

res := &ResultType: "findAllString"

Result 中使用大写字母,因为您的types 映射还包含带有大写字母的值:

res := &ResultType: "FindAllString"

这样您就可以获得所需的输出(在Go Playground 上尝试):

2009/11/10 23:00:00 
    <select name="type">
                <option value="FindAllString" selected>FindAllString</option>
                <option value="FindString">FindString</option>
                <option value="FindStringSubmatch">FindStringSubmatch</option>
    </select>

另请注意,您可以像这样简单地编写循环:

range $key, $value := .Types
    <option value="$key"if eq $key $.Res.Type selectedend>.</option>
end

另请注意,出于测试目的,您可以简单地将os.Stdout 作为模板执行的编写者传递,您将在控制台上看到结果,而无需创建和使用缓冲区,例如:

err = t.Execute(os.Stdout, struct 
    Types map[string]string
    Res   *Result
types, res)

在Go Playground 上试用简化版。

阅读此答案以获得更多见解:golang template engine pipelines

【讨论】:

以上是关于比较 Go 模板中的两个变量的主要内容,如果未能解决你的问题,请参考以下文章

为什么在相同的比较模板函数中有两个不同的答案

如何比较 Django 模板中的两个查询集?

Go中的struct比较知识点

如何将上下文变量与 Django 模板中的 SQL ID 进行比较?

Go反射中的type和kind比较

Go反射中的type和kind比较