在Go条件模板中使用自定义功能 [英] Using custom func in Go condition template

查看:62
本文介绍了在Go条件模板中使用自定义功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试定义一个自定义的Go函数,以在模板条件中使用.我要实现的是:如果给定的参数是IPv4地址,则模板将输出 IPv4:[argument] ,否则它将输出 IPv6:[argument] .

为此,我创建了一个像这样的模板:

  {{range .Addresses}}{{如果是IsIPv4.}}IPv4:{{.}}{{ 别的 }}IPv6:{{}}{{ 结尾 }}{{ 结尾 }} 

如您所见,我创建了一个名为 IsIPv4 的新函数,该函数接受字符串参数,并给该参数返回true或false.这是代码:

  var(errNotAnIPAddress = errors.New(参数不是IP地址"))func isIPv4(地址字符串)(布尔型,错误){ip:= net.ParseIP(地址)如果ip == nil {返回false,errNotAnIPAddress}return(ip.To4()!=无),无} 

在执行模板时,我没有任何错误,但是在尝试评估 {{如果为IsIPv4时,则似乎停止了执行.}} .

当然,在尝试解析和执行模板之前已对函数进行了映射.

  funcMap:= template.FuncMap {"IsIPv4":isIPv4,} 

我刚开始使用Go,可能已经错过了一些东西(也许很明显?).

为了进行一点调试,我尝试删除模板中的IsIPv4调用,并给出类似 {{if的条件.}} .结果是始终输出 IPv4:[IP地址] .这对我来说很有意义.

我还查看了预定义的Go功能,例如 eq ,看来我正在尝试重现相同的想法,但没有成功.

解决方案

TL; DR; ,您必须检查error 值://golang.org/pkg/text/template/#Template.Execute"rel =" nofollow noreferrer> template.Execute()

另一个潜在的错误是 isIPv4()期望值为 string 类型的值,并且您可以传递其他类型的值.

并且为模板注册的自定义函数仅在您打算停止执行模板时才返回非 nil 错误.因为如果您返回 error ,就会发生这种情况. template.FuncMap :

[...]如果在执行过程中第二个(错误)返回值的计算结果为非零,则执行终止,并且Execute返回该错误.

工作示例

这是一个使用您的模板和 isIPv4()函数的工作示例:

  t:= template.Must(template.New(").Funcs(template.FuncMap {"IsIPv4":isIPv4,}).Parse(templ))m:= map [string] interface {} {地址":[] string {"127.0.0.1","0:0:0:0:0:0:0:0:1"},}如果err:= t.Execute(os.Stdout,m);err!= nil {恐慌} 

输出(在游乐场上尝试):

  IPv4:127.0.0.1IPv6:0:0:0:0:0:0:0:1 

潜在错误

上面的程序显示以下错误:

传递无效的IP:

 地址":[] string {"127.0.0.1.9"}, 

输出:

  panic:模板::2:6:在< IsIPv4处执行".> ;:调用IsIPv4时出错:该参数不是IP地址 

传递非字符串值:

 地址":[] interface {} {2}, 

输出:

  panic:模板::2:13:在<处执行".预期字符串;懂了 

解析模板后尝试注册自定义函数 :

  t:= template.Must(template.New(").Parse(templ))t.Funcs(template.FuncMap {"IsIPv4":isIPv4,}) 

输出:

  panic:模板:: 2:未定义函数"IsIPv4" 

I'm trying to define a custom Go func to use in a template condition. What I want to achieve is : if the given argument is an IPv4 address the template will output IPv4: [argument] else it will output IPv6: [argument].

To do that I have created a template like this:

{{ range .Addresses }}
{{ if IsIPv4 . }}
IPv4: {{ . }}
{{ else }}
IPv6: {{ . }}
{{ end }}
{{ end }}

As you can see I have create a new function called IsIPv4 which take a string argument and given the argument return true or false. Here is the code:

var (
    errNotAnIPAddress = errors.New("The argument is not an IP address")
)

func isIPv4(address string) (bool, error) {
    ip := net.ParseIP(address)

    if ip == nil {
        return false, errNotAnIPAddress
    }

    return (ip.To4() != nil), nil
}

When executing my template I have got no errors but the execution looks like to stop when trying to evaluate {{ if IsIPv4 . }}.

Of course the function is mapped before trying to parse and execute the template.

funcMap := template.FuncMap{
    "IsIPv4": isIPv4,
}

I'm pretty new to Go and I have probably missed something (maybe obvious?).

To debug a little bit I have tried to remove the IsIPv4 call in my template giving a condition like {{ if . }}. And the result was to always output IPv4: [the IP address]. That makes sense to me.

I also took a look at the predefined Go funcs like eq and it looks like I'm trying to reproduce the same idea, without any success.

解决方案

TL;DR; You must inspect the error value returned by template.Execute() or template.ExecuteTemplate() which will tell you why it doesn't work for you.


Things that could go wrong

First, your execution doesn't panic because it simply returns an error. Would you inspect that, you'll probably know what's going wrong immediately:

if err := t.Execute(os.Stdout, data); err != nil {
    panic(err)
}

Next what could go wrong: you have to register your custom functions prior to parsing the template because the template engine needs to be able to statically analyze the template, and it needs to know prior that IsIPv4 is a function name:

t := template.Must(template.New("").Funcs(template.FuncMap{
    "IsIPv4": isIPv4,
}).Parse(templ))

Another potential error is that isIPv4() expects a value of type string, and you may pass a value of different type.

And custom functions registered for templates should only return a non-nil error if you intend to stop the execution of the template. Because that's what happens if you return an error. template.FuncMap:

[...] if the second (error) return value evaluates to non-nil during execution, execution terminates and Execute returns that error.

Working example

Here's a working example using your template and your isIPv4() function:

t := template.Must(template.New("").Funcs(template.FuncMap{
    "IsIPv4": isIPv4,
}).Parse(templ))

m := map[string]interface{}{
    "Addresses": []string{"127.0.0.1", "0:0:0:0:0:0:0:1"},
}

if err := t.Execute(os.Stdout, m); err != nil {
    panic(err)
}

Output (try it on the Go Playground):

IPv4: 127.0.0.1

IPv6: 0:0:0:0:0:0:0:1

Potential errors

The above program prints the following errors:

Passing an invalid IP:

    "Addresses": []string{"127.0.0.1.9"},

Output:

panic: template: :2:6: executing "" at <IsIPv4 .>: error calling IsIPv4:
    The argument is not an IP address

Passing a non-string value:

    "Addresses": []interface{}{2},

Output:

panic: template: :2:13: executing "" at <.>: wrong type for value; expected string; got int

Attempting to register your custom function after the template has been parsed:

t := template.Must(template.New("").Parse(templ))
t.Funcs(template.FuncMap{
    "IsIPv4": isIPv4,
})

Output:

panic: template: :2: function "IsIPv4" not defined

这篇关于在Go条件模板中使用自定义功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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