比较Go模板中的两个变量 [英] Compare two variables inside Go template

查看:648
本文介绍了比较Go模板中的两个变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在传递给我的模板的数据中,我有两个变量 Type Res.Type 我想比较预先选择我的选择字段。

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



<$









$b / b
html / template
日志


类型结果struct {类型字符串}

func main(){
类型:= map [string] string {
FindAllString:FindAllString,
FindString:FindString,
FindStringSubmatch:FindStringSubmatch,
}
res:=& Result {类型: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 {
类型map [string] string
Res * Result
} {types,res})
if err!= nil {












$ b $ / code $>

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

  panic:template:index:4:21:在< .Res.Type>执行index:无法计算字段Res中的类型字符串

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
退出状态2

当我比较两个正常字符串时,它的作用是,但我想知道如果有这样一种习惯性的方式。我已经看到你可以在模板中添加一个函数,但是我觉得必须有一个更简单的方法。

解决方案

问题在于即使使用 {{range}} 动作也会更改(设置)点()循环变量( $ key $ value )。在 {{range}} 内,点设置为当前元素。 c> {{range}} 你写:

  {{if eq $ key .Res。类型}} 

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



<使用 $ 标记不引用循环值,而是引用传递给模板执行的参数:

  {{if eq $ key $ .Res.Type}} 

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

  res:= & Result {类型:findAllString} 

中使用大写字母结果作为您的类型地图也包含大写字母的值:

 水库:=& Result {Type:FindAllString} 

它在 Go Playground 上):

  2009/11/10 23:00:00 
< select name =type>
< option value =FindAllStringselected> 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}}已选择{{end}}> {{。}}< / option>
{{end}}

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

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

试试 Go Playground



阅读此答案获取更多见解: golang模板引擎管道


In the data I pass to my template I have the two variables Type and Res.Type I want to compare to preselect an option for my select field.

To illustrate my problem I have created this simplified version:

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 := &Result{Type: "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())
}

It should select the "FindAllString" option but it only generates the error

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

When I just compare two normal strings it works but I want to know if there is an idomatic way to do this. I have seen that you could add a function to the template but I feel that there must be a simpler way for this.

解决方案

The problem is that the {{range}} action changes (sets) the dot (.) even if you use loop variables ($key and $value) in your case. Inside a {{range}} the dot is set to the current element.

And inside {{range}} you write:

{{ if eq $key .Res.Type }}

Since values in your loop are string values, .Res.Type is an error, because there is no Res field or method of a string value (the current element denoted by the dot .).

Use the $ sign to not refer to the loop value, but to the param passed to the template execution:

{{ if eq $key $.Res.Type }}

This will work, but won't give you the desired output, as you have a typo:

res := &Result{Type: "findAllString"}

Use capital letter in Result as your types map also contains values with capital letter:

res := &Result{Type: "FindAllString"}

With this you get the desired output (try it on the 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>

Also note that you could simply write the loop like this:

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

Also note that for testing purposes you may simply pass os.Stdout as the writer for template execution, and you'll see the result on your console without having to create and use a buffer, e.g.:

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

Try the simplified version on the Go Playground.

Read this answer for more insights: golang template engine pipelines

这篇关于比较Go模板中的两个变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆