Шаблон Golang и тестирование допустимых полей

В пакете Go database/sql есть множество структур Null[Type], которые помогают отображать значения базы данных (и их возможные нулевые значения) в код. Я пытаюсь выяснить, как проверить, является ли структура field нулевой или, другими словами, когда ее свойство Valid имеет значение false.

Рекомендуемый способ печати поля SQL — использовать свойство .Value, например:

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

Это прекрасно работает.

Но предположим, что у меня есть что-то более сложное, где мне нужно сравнить значение с чем-то другим, например:

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

Как оказалось, это тоже отлично работает, если только .MyField не является действительным, и в этом случае я получаю сообщение об ошибке «ошибка вызова eq: недопустимый тип для сравнения». Ошибка имеет смысл, потому что Go не может сравнивать поле nil с другим значением (или что-то в этом роде).

Я бы подумал, что «простым» решением будет сначала проверить, равно ли значение nil, а затем сравнить его с тем, что мне нужно, например так:

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

В этом случае я получаю ту же «ошибку при вызове eq: неверный тип для сравнения». Я предполагаю, что это означает, что .MyField «существует», хотя значение .MyField не является действительным. Итак, затем я перепробовал полдюжины других версий, в основном с той же ошибкой, например:

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

В этот момент я понимаю, что действительно не понимаю, как вообще проверить существование допустимого поля. Я был бы признателен за любую помощь, которую вы могли бы оказать.

Спасибо.


person Brent    schedule 04.07.2018    source источник


Ответы (1)


Функция and в шаблонах Go не оценивается методом короткого замыкания (в отличие от оператора && в Go), все ее аргументы оцениваются всегда. Цитата из документа пакета text/template:

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.

Это означает, что ваше {{if}} действие:

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

Даже несмотря на то, что условие будет оцениваться как false, если $.MyStruct.MyField равно nil, но eq $.MyStruct.MyField.Value . также будет оцениваться и приведет к ошибке, которую вы получите.

Вместо этого вы можете встроить несколько действий {{if}}, например:

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

Вы также можете использовать действие {{with}}, но оно также устанавливает точку, поэтому вы должны быть осторожны:

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

Примечание.

Вы говорили о значениях nil в своем вопросе, но типы sql.NullXX - это структуры, которые не могут быть nil. В этом случае вы должны проверить его поле Valid, чтобы узнать, вернет ли его метод Value() значение, отличное от nil, при вызове. Это может выглядеть так:

{{if $.MyStruct.MyField.Valid}}
    {{if eq $.MyStruct.MyField.Value .}}selected="selected"{{end}}
{{end}}
person icza    schedule 04.07.2018
comment
Отлично, спасибо icza! Единственное небольшое изменение, которое мне нужно было сделать — и я не уверен, почему — это добавить .Valid к первому условию if, например: {{ if $.MyStruct.MyField.Valid }} {{if eq $. MyStruct.MyField.Value .}}selected=selected{{end}}{{end}}. С этим, этот шаблон, наконец, работает. - person Brent; 04.07.2018
comment
@Brent Тогда похоже, что вы используете не указатели на структуры, а значения структур. В своем вопросе вы имели в виду значения nil, и только указатели имеют значения nil, а не структуры. Смотрите отредактированный ответ. - person icza; 04.07.2018