我正在尝试包装html / template,因此除了要渲染的数据外,我还保证我的模板中有某些数据(例如会话数据)。但是,我目前的方法是......有缺陷的。以下是一个简化示例:
package main
import "fmt"
import "os"
import "html/template"
func main() {
// Passing nil directly to Execute doesn't render anything for missing struct fields
fmt.Print("Directly rendering nil\n")
tmpl, err := template.New("master").Parse("Foo is: {{.Data.Foo}}")
if err != nil {
fmt.Printf(err.Error())
return
}
err = tmpl.Execute(os.Stdout, nil)
if err != nil {
fmt.Printf(err.Error())
return
}
// Wrapping templates works as long as I supply data...
fmt.Print("\nRendering Foo\n")
render(struct {
Foo string
}{
"foo",
})
// ...but this breaks.
fmt.Print("\nRendering nil\n")
render(nil)
}
func render(data interface{}) {
allData := struct {
Session string
Data interface{}
}{
"sessionData",
data,
}
// Hardcoded template for the example - this could be any arbitrary template
tmpl, err := template.New("master").Parse("Foo is: {{.Data.Foo}}")
if err != nil {
fmt.Printf(err.Error())
return
}
err = tmpl.Execute(os.Stdout, allData)
if err != nil {
fmt.Printf(err.Error())
return
}
}
我得到以下输出:
Directly rendering nil
Foo is:
Rendering Foo
Foo is: foo
Rendering nil
Foo is: template: master:1:15: executing "master" at <.Data.Foo>: nil pointer evaluating interface {}.Foo
所以我不太确定首先发生了什么 - 为什么html /模板能够处理传递nil
,但无法形象用nil指针做什么?
其次,有没有更好的方法来解决这个问题?
答案 0 :(得分:1)
最好的办法是始终将数据设为地图或结构,方法是将类型设为地图或结构,或者不使用带interface{}
的nil:
package main
import "fmt"
import "os"
import "text/template"
func main() {
tmpl, err := template.New("master").Parse("{{if .Data.Foo}}Foo is: {{.Data.Foo}}{{else}}Foo is empty{{end}}")
if err != nil {
fmt.Printf(err.Error())
return
}
err = tmpl.Execute(os.Stdout, nil)
if err != nil {
fmt.Printf(err.Error())
return
}
fmt.Println("")
err = tmpl.Execute(os.Stdout, struct {
Session string
Data map[string]string
}{
"sessionData",
nil,
})
if err != nil {
fmt.Printf(err.Error())
return
}
fmt.Println("")
err = tmpl.Execute(os.Stdout, struct {
Session string
Data interface{}
}{
"sessionData",
map[string]string{},
})
if err != nil {
fmt.Printf(err.Error())
return
}
fmt.Println("")
}
播放:http://play.golang.org/p/9GkAp6ysvD
至于它为何如此工作,它有点复杂,你必须查看代码:https://golang.org/src/text/template/exec.go?s=4647:4717#L521
当使用nil调用execute时,reflect.ValueOf(nil)
返回一个无效的值,因此evalField返回零值,最后得到一个空字符串。
但是,当使用有效结构调用execute时,首先反映.ValueOf返回有效值。 .Data
命令在传递给Execute的整个struct上调用evalField,evalField调用FieldByIndex / FieldByName来获取&#34; Data&#34;领域。这不会返回无效的值。
接下来,当评估.Foo
时,如果Data是一个接口或一个指针,indirect函数会跟随它到最后,如果它发现它是nil,它就会失败有这个错误。
当数据是地图时,间接功能不做任何事情,并且它不会失败。
这可能是文本/模板包中的错误。