Golang template and testing for Valid fields

回眸只為那壹抹淺笑 提交于 2019-12-19 09:03:25

问题


In Go's database/sql package, there are a bunch of Null[Type] structs that help map database values (and their possible nulls) into code. I'm trying to figure out how to test whether a struct field is null, or in other words, when its Valid property is false.

The recommended way to print a SQL field is to use the .Value property, like this:

<div>{{ .MyStruct.MyField.Value }}</div>

This works great.

But suppose I have something slightly more complicated, where I need to test the value against something else, for example:

<select name="y">
   {{ range .SomeSlice }}
       <option value="{{ . }}" {{ if eq $.MyStruct.MyField.Value .}}selected="selected"{{ end }}>{{ . }}</option>
   {{ end }}
</select>

As it happens, this works great, too, unless .MyField is not Valid, in which case I get the error, "error calling eq: invalid type for comparison". The error makes sense, because Go can't compare a nil Field against another value (or something like that).

I would have thought the 'easy' solution would be to test first whether the Value is nil, and then compare it against what I need, like this:

<select name="y">
   {{ range .SomeSlice }}
       <option value="{{ . }}" {{ if and ($.MyStruct.MyField) (eq $.MyStruct.MyField.Value .)}}selected="selected"{{ end }}>{{ . }}</option>
   {{ end }}
</select>

In this case, I get the same "error calling eq: invalid type for comparison". I guess that means .MyField "exists" even though the value of .MyField is not Valid. So, then I tried a half dozen other versions, mostly with the same error, for example:

<select name="y">
   {{ range .SomeSlice }}
       <option value="{{ . }}" {{ if and ($.MyStruct.MyField.Valid) (eq $.MyStruct.MyField.Value .)}}selected="selected"{{ end }}>{{ . }}</option>
   {{ end }}
</select>

At this point, I'm realizing I really don't understand how to test for the existence of a valid field at all. I'd appreciate any help you might have.

Thanks.


回答1:


The and function in Go templates is not short-circuit evaluated (unlike the && operator in Go), all its arguments are evaluated always. Quoting from text/template package doc:

and
    Returns the boolean AND of its arguments by returning the
    first empty argument or the last argument, that is,
    "and x y" behaves as "if x then y else x". All the
    arguments are evaluated.

This means that the {{if}} action of yours:

{{ if and ($.MyStruct.MyField) (eq $.MyStruct.MyField.Value .)}}

Even though the condition would be evaluated to false if $.MyStruct.MyField is nil, but eq $.MyStruct.MyField.Value . will also be evaluated and result in the error you get.

Instead you may embed multiple {{if}} actions, like this:

{{if $.MyStruct.MyField}}
    {{if eq $.MyStruct.MyField.Value .}}selected="selected"{{end}}
{{end}}

You may also use the {{with}} action, but that also sets the dot, so you have to be careful:

<select name="y">
   {{range $idx, $e := .SomeSlice}}
       <option value="{{.}}" {{with $.MyStruct.MyField}}
               {{if eq .Value $e}}selected="selected"{{end}}
           {{end}}>{{.}}</option>
   {{end}}
</select>

Note:

You were talking about nil values in your question, but the sql.NullXX types are structs which cannot be nil. In which case you have to check its Valid field to tell if its Value() method will return you a non-nil value when called. It could look like this:

{{if $.MyStruct.MyField.Valid}}
    {{if eq $.MyStruct.MyField.Value .}}selected="selected"{{end}}
{{end}}


来源:https://stackoverflow.com/questions/51165642/golang-template-and-testing-for-valid-fields

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!