英文:
Presence of unrelated method in interface breaks text/template?
问题
Playground链接:http://play.golang.org/p/Ebf5AuJlcP
type Foo interface {}
type Bar interface {
ThisIsABar()
}
// Person 实现了 Foo 和 Bar 接口
type Person struct {
Name string
}
func (p Person) ThisIsABar() {}
type FooContext struct {
Something Foo
}
type BarContext struct {
Something Bar
}
func main() {
t := template.Must(template.New("test").Parse("{{ .Something.Name }}\n"))
// 这个可以正常工作。
if err := t.Execute(os.Stdout, FooContext{Person{"Timmy"}}); err != nil {
fmt.Printf("Error: %s\n", err)
}
// 使用包含相同 Person 对象但是包装在不同接口中的 BarContext,会报错。
if err := t.Execute(os.Stdout, BarContext{Person{"Timmy"}}); err != nil {
fmt.Printf("Error: %s\n", err)
}
}
当我渲染一个包含 {{ .Something.Name }}
的模板(通过 text/template
包),通过不包含任何方法的接口 Foo
进行渲染时,一切正常。但是,如果我改为使用接口 Bar
,即使这个接口上有一个无关的方法且并未使用,我会得到以下错误信息:
executing "test" at <.Something.Name>: can't evaluate field Name in type main.Bar
为什么接口上存在一个无关的方法会影响模板的渲染呢?
英文:
Playground link: http://play.golang.org/p/Ebf5AuJlcP
type Foo interface {}
type Bar interface {
ThisIsABar()
}
// Person implements both Foo and Bar
type Person struct {
Name string
}
func (p Person) ThisIsABar() {}
type FooContext struct {
Something Foo
}
type BarContext struct {
Something Bar
}
func main() {
t := template.Must(template.New("test").Parse("{{ .Something.Name }}\n"))
// This works fine.
if err := t.Execute(os.Stdout, FooContext{Person{"Timmy"}}); err != nil {
fmt.Printf("Error: %s\n", err)
}
// With BarContext, containing the exact same Person but wrapped in a
// different interface, it errors out.
if err := t.Execute(os.Stdout, BarContext{Person{"Timmy"}}); err != nil {
fmt.Printf("Error: %s\n", err)
}
}
When I render a template (via the text/template
package) containing {{ .Something.Name }}
, I can go through interface Foo
which contains no methods, and it works fine. But if I go through interface Bar
instead, I get:
executing "test" at <.Something.Name>: can't evaluate field Name in type main.Bar
Why does the presence of an unrelated method on the interface, that isn't even used, affect the rendering of the template?
答案1
得分: 6
text/template对interface{}进行了特殊处理,所谓的函数可以具有返回类型interface{}等。向接口添加方法意味着不再触发检测。
http://golang.org/src/pkg/text/template/exec.go#L323
323 for _, cmd := range pipe.Cmds {
324 value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
325 // If the object has type interface{}, dig down one level to the thing inside.
326 if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
327 value = reflect.ValueOf(value.Interface()) // lovely!
328 }
329 }
BarContext.Something是一个Bar(一个接口)。Bar没有Name字段。如果你想在那里使用一个接口,你需要通过接口的一个方法提供数据。
英文:
text/template is special casing interface{}, so called functions can have return type interface{}, etc. Adding a method to your interface means that detection no longer triggers.
http://golang.org/src/pkg/text/template/exec.go#L323
323 for _, cmd := range pipe.Cmds {
324 value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
325 // If the object has type interface{}, dig down one level to the thing inside.
326 if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
327 value = reflect.ValueOf(value.Interface()) // lovely!
328 }
329 }
BarContext.Something is a Bar (an interface). A Bar has no field Name. If you want to use an interface there, you'll need to provide the data via a method that is part of the interface.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论