gpt4 book ai didi

go - 模板中的 Nil 指针求值...为什么?有更好的策略吗?

转载 作者:IT王子 更新时间:2023-10-29 01:42:17 28 4
gpt4 key购买 nike

我正在尝试包装 html/template,因此除了我要呈现的数据之外,我保证在我的模板中有某些数据(例如 session 数据)。但是,我目前的方法是……有缺陷的。下面是一个简化的示例:

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/template 能够处理传递的 nil,但无法弄清楚如何处理一个零指针?

其次,有没有更好的方法来解决这个问题?

最佳答案

最好的办法是始终将 Data 设为映射或结构,方法是将类型设为映射或结构,或者不将 nil 与 interface{} 一起使用:

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 时,首先 reflect.ValueOf 会返回一个有效值。 .Data 命令在您传递给 Execute 的整个结构上调用 evalField,evalField 调用 FieldByIndex/FieldByName 以获取“数据”字段。这不会返回无效值。

接下来,当 .Foo 被求值时,如果 Data 是一个接口(interface)或指针,indirect函数一直跟踪它到最后,如果发现它为 nil,则失败并出现此错误。

当 Data 是一个 map 时,indirect 函数什么都不做,也不会失败。

这可能是文本/模板包中的错误。

关于go - 模板中的 Nil 指针求值...为什么?有更好的策略吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35930770/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com