Closed
Description
package main
import (
"bytes"
"fmt"
"log"
"text/template"
)
type Niller interface {
Nil() Niller
}
type Nill struct {
nilv Niller
}
func (n Nill) Nil() Niller {
return n.nilv
}
func main() {
tmpl, err := template.New("").Parse(`{{ .Nil }}: {{ with .Nil }}Failed, got {{ . }}{{ else }}OK{{ end }}`)
if err != nil {
log.Fatal(err)
}
var (
nil1 Niller = (*Nill)(nil)
nil2 Niller
nil3 *Nill
nil4 Niller = nil
)
for i, niller := range []Niller{nil1, nil2, nil3, nil4} {
var buff bytes.Buffer
err = tmpl.Execute(&buff, &Nill{nilv: niller})
if err != nil {
log.Fatal(err)
}
fmt.Println(i+1, buff.String())
}
}
The above prints:
1 <nil>: Failed, got <nil>
2 <nil>: OK
3 <nil>: Failed, got <nil>
4 <nil>: OK
This issue makes more sense if you also glance at these:
- text/template: panics on method on nil interface value #30143 panic on nil interface value; it was when implementing workarounds for that issue that I got other curious nullpointers which I had hard time understanding. Unfortunately I found no workarounds that both avoid panics and work sensible with
if
andwhere
. - text/template: allow callers to override IsTrue #28391 about the subjective truth in
template.IsTrue
The documentation for both if
and with
is similar:
"If the value of the pipeline is empty, no output is generated"
I'm not sure what the definition of "empty" in the above, but as all of the above cases outputs <nil>
, I assume it is the truthines defined in template.IsTrue
that is used.