我尝试定义要在模板条件中使用的自定义Go功能。 我想要实现的是:如果给定的参数是IPv4地址,模板将输出 IPv4:[argument] 否则它将输出 IPv6:[argument] 。
为此,我创建了一个这样的模板:
{{ range .Addresses }}
{{ if IsIPv4 . }}
IPv4: {{ . }}
{{ else }}
IPv6: {{ . }}
{{ end }}
{{ end }}
正如您所看到的,我创建了一个名为 IsIPv4 的新函数,它接受一个字符串参数并给出参数返回true或false。这是代码:
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
}
执行我的模板时,我没有错误,但是当尝试评估 {{if IsIPv4时,执行似乎停止了。 }}
当然,在尝试解析和执行模板之前,会映射函数。
funcMap := template.FuncMap{
"IsIPv4": isIPv4,
}
我是Go的新手,我可能错过了一些东西(可能很明显?)。
为了调试一点,我试图在我的模板中删除IsIPv4调用,给出类似 {{if。 }} 即可。结果是始终输出 IPv4:[IP地址] 。这对我来说很有意义。
我还看了一下预定义的Go功能,比如 eq ,看起来我试图重现同样的想法,没有任何成功。
答案 0 :(得分:1)
TL; DR; 您必须检查template.Execute()
或template.ExecuteTemplate()
返回的error
值,它会告诉您为什么它不起作用你。
首先,您的执行并不会引起恐慌,因为它只会返回错误。你会检查一下,你可能会立即知道出了什么问题:
if err := t.Execute(os.Stdout, data); err != nil {
panic(err)
}
接下来可能出现的问题是:您必须先注册自定义函数 来解析模板,因为模板引擎需要能够静态分析模板,并且需要事先了解{ {1}}是一个函数名称:
IsIPv4
另一个潜在错误是t := template.Must(template.New("").Funcs(template.FuncMap{
"IsIPv4": isIPv4,
}).Parse(templ))
期望值为isIPv4()
的值,您可以传递不同类型的值。
如果您打算停止执行模板,则为模板注册的自定义函数应仅返回非string
错误。因为如果您返回nil
会发生什么。 template.FuncMap
:
[...]如果第二个(错误)返回值在执行期间计算为非nil,则执行终止,Execute返回该错误。
以下是使用您的模板和error
函数的工作示例:
isIPv4()
输出(在Go Playground上尝试):
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)
}
上述程序会输出以下错误:
传递无效的IP:
IPv4: 127.0.0.1
IPv6: 0:0:0:0:0:0:0:1
输出:
"Addresses": []string{"127.0.0.1.9"},
传递非panic: template: :2:6: executing "" at <IsIPv4 .>: error calling IsIPv4:
The argument is not an IP address
值:
string
输出:
"Addresses": []interface{}{2},
在解析模板后,尝试注册自定义函数:
panic: template: :2:13: executing "" at <.>: wrong type for value; expected string; got int
输出:
t := template.Must(template.New("").Parse(templ))
t.Funcs(template.FuncMap{
"IsIPv4": isIPv4,
})