How can I conditionally set a variable in a Go template based on an expression which may cause an error if not wrapped with an if statement
我该怎么做?
1 | {{ $use_ssl := (ne $.Env.CERT_NAME"") }} |
其中,
1 | at <ne $.Env.CERT_NAME"">: error calling ne: invalid type for comparison |
注意:我无法控制传入Go模板的对象,因此必须完全在模板本身内解决这个问题。
我试过什么我试着先检查一下它是否是非空的:
1 | {{ $use_ssl := ( ($.Env.CERT_NAME) && (ne $.Env.CERT_NAME"") ) }} |
但它给出了这个错误:
1 | unexpected"&" in operand |
所以我切换到这个,它在语法上是允许的:
1 | {{ $use_ssl := (and ($.Env.CERT_NAME) (ne $.Env.CERT_NAME"") ) }} |
但是,我失去了用
1 | at <ne $.Env.CERT_NAME ...>: error calling ne: invalid type for comparison |
好吧,我想,如果我不能用一条漂亮的单行线来做,而且Go没有三元运算符,那很好,我就用惯用的Go-Way来做,显然是
1 2 3 4 5 | {{ if $.Env.CERT_NAME }} {{ $use_ssl := (ne $.Env.CERT_NAME"") }} {{ else }} {{ $use_ssl := false }} {{ end }} |
但是,当然,我遇到了范围问题,因为
1 2 3 4 5 6 | {{ if $.Env.CERT_NAME }} {{ $use_ssl := true }} {{ else }} {{ $use_ssl := false }} {{ end }} # $use_ssl: {{ $use_ssl }} |
现在不出现此错误:
1 | undefined variable"$use_ssl" |
"不出汗",我想。我将在外部作用域中声明变量,这样它将具有正确的作用域,并且内部作用域仍然能够更改该变量(具有外部作用域的变量)。(顺便说一下,这就是它在Ruby中的工作原理。)
不,很明显,只创建了两个同名但作用域不同的变量(这怎么会让人困惑!):
1 2 3 4 5 6 7 8 9 10 11 | {{ $use_ssl := false }} {{ if $.Env.CERT_NAME }} {{ $use_ssl := true }} # $use_ssl: {{ $use_ssl }} {{ else }} {{ $use_ssl := false }} {{ end }} # $use_ssl: {{ $use_ssl }} # $use_ssl: true # $use_ssl: false |
我也试过将if语句嵌入如下:
1 | {{ $use_ssl := if $.Env.CERT_NAME { true } }} |
但这就产生了这个错误:
1 | unexpected <if> in command |
显然,
如果我尝试用C的三元运算符的惯用go等价物中建议的三元运算符的各种替代方法,我也会遇到语法错误。,像:
1 | c := map[bool]int{true: 1, false: 0} [5 > 4] |
当然,使用
我错过了什么?这在Go模板中是可能的吗?
Go模板(我是新手)似乎非常有限。在一个模板中,几乎你能在Go本身中做的所有事情都是不可能的。但希望有个解决办法…
http://play.golang.org/p/sufzdsx-1v有一个巧妙的解决方法,包括用
https://groups.google.com/forum/!主题/Golang Nuts/Muznz9dbhrg
This is the biggest (and only) problem I have with Go. I simply do not understand why this functionality has not been implemented yet.
When the template package is used in a generic context (eg. Executing
an arbitrary template file with an arbitrary json file), you might not
have the luxury of doing precalculations.
网址:https://github.com/golang/go/issues/10608
This is probably as designed, but it would be really nice if there was a way to get the changed $v outside of the conditional.
This is the #1 template question we get over at Hugo (https://github.com/spf13/hugo). We have added a hack [
$.Scratch.Set"v1" 123 ] to work around it for now ...
当前正在使用的解决方案
如果更新作用域而不是声明变量,无论是使用
1 2 3 4 5 6 7 8 | {{- if eq .podKind"core" -}} {{- $dummy := set ."matchNodePurpose" .Values.scheduling.corePods.nodeAffinity.matchNodePurpose }} {{- else if eq .podKind"user" -}} {{- $dummy := set ."matchNodePurpose" .Values.scheduling.userPods.nodeAffinity.matchNodePurpose }} {{- end -}} # Will now output what you decided within an if/else if clause {{- .matchNodePurpose }} |
未来解决方案(可与Helm 2.10一起使用)
我在helm模板的上下文中遇到了同样的问题,这些模板是带有一些预先安装的附加功能(如sprig)的go模板。
2018年3月28日,在本次公关中,一位Terenary运营商加入了Sprig,到时候,Helm会让他们解决您和我都有的问题。
万亿进制
我想我可能已经为我的特定问题找到了一个解决方法,尽管我希望听到其他更普遍地解决这个问题的答案。
在https://github.com/jwilder/nginx proxy/blob/1e0b930/nginx.tmpl_l91中遇到这一行:
1 | {{ $default_host := or ($.Env.DEFAULT_HOST)"" }} |
这给了我另一个尝试的想法。我想解决方案是使用
1 2 | {{ $cert_name := or $.Env.CERT_NAME"" }} {{ $use_ssl := ne $cert_name"" }} |