Go 模板中的零指针计算…为什么?有更好的策略吗?
我正在尝试包装html/模板,因此我保证除了要呈现的数据之外,我的模板中还包含某些数据(例如会话数据)。然而,我目前的方法……有缺陷。下面是一个简化的示例:Go 模板中的零指针计算…为什么?有更好的策略吗?,go,go-templates,Go,Go Templates,我正在尝试包装html/模板,因此我保证除了要呈现的数据之外,我的模板中还包含某些数据(例如会话数据)。然而,我目前的方法……有缺陷。下面是一个简化的示例: package main import "fmt" import "os" import "html/template" func main() { // Passing nil directly to Execute doesn't render anything for missing struct fields f
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
直接渲染nil
富是:
渲染Foo
福是:福
呈现零
Foo是:template:master:1:15:在:nil指针处执行“master”求值接口{}.Foo
因此,我不太清楚首先发生了什么-为什么html/template能够处理传递的nil
,但却不知道如何使用nil指针
其次,有没有更好的方法来解决这个问题?您最好的办法是始终将数据设置为映射或结构,方法是将类型设置为映射或结构,或者不将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("")
}
播放:
至于为什么它是这样工作的,有点复杂,你必须看看代码:
当使用nil调用execute时,reflect.ValueOf(nil)
返回一个无效值,因此evalField返回零值,结果是一个空字符串
但是,当使用有效结构调用execute时,第一个reflect.ValueOf将返回一个有效值。.Data
命令对传递给执行的整个结构调用evalField,evalField调用FieldByIndex/FieldByName以获取“数据”字段。这不会返回无效值
接下来,当计算.Foo
时,如果数据是一个接口或指针,函数将跟随它直到结束,如果它发现它为零,它将失败并出现此错误
当数据是映射时,间接函数不做任何事情,也不会失败
这可能是文本/模板包中的一个错误。这可能是一个错误,如果没有,请尝试使用Go1.6,否则请尝试提交一个错误。