问题描述
使用golang html / template (与 text / template 相同的行为)。如果我有一个具有接口类型的成员的结构,我不能访问底层类型的成员(特别是试图访问实现接口 InnerInterface 但通过 InnerInterface 接口类型返回,而不是结构类型)。
包主
导入fmt
导入os
导入html / template
类型InnerInterface接口{InnerSomeMethod()}
类型MyInnerStruct结构{标题字符串}
func(mis MyInnerStruct)InnerSomeMethod(){fmt.Println(只是为了表明我们正在满足界面)}
type MyOuterStruct struct {Inner InnerInterface}
func main(){
fmt.Println(Starting )
arg:= MyOuterStruct {Inner:MyInnerStruct {标题:test1}}
err:= t emplate.Must(template.New(testtmpl)。Parse({{。Inner.Title}}))。Execute(os.Stdout,arg)
if err!= nil {panic(err) }
$ b
更改: type MyOuterStruct struct {Inner InnerInterface} 为一个完全通用的接口,即类型MyOuterStruct struct {Inner interface {}} 使其正确呈现。这使我相信 interface {} 会被渲染引擎专门处理。
有没有更好的方法要做到这一点,而不是使用 interface {} ,只要我希望能够动态地评估这样的字段?
您说的 interface {} 由渲染
引擎处理的方式是正确的。只有 interface {} 值被解压缩,但有一个方法设置的接口值不是。
我想这背后的原因是,如果你有一个接口类型,你特别限制类型的方法集。因此,您不希望模板引擎尝试访问可能位于该接口后面的成员。
'问题'是由函数中:
func indirect(v reflect.Value)(rv reflect.Value,isNil bool){
for; v.Kind()== reflect.Ptr || v.Kind()== reflect.Interface; v = v.Elem(){
if v.IsNil(){
return v,true
}
如果v.Kind()== reflect.Interface&& amp ; v.NumMethod()> 0 {
break
}
}
return v,false
}
调用此方法以获得反射值的最深值。
假设你在一个指针上有一个指针,这个函数将返回
中的最后一个。接口值也是一样。关键在于,只要
接口值具有多于0个方法,间接停止在那里。完全是你所描述的
行为。
由于这似乎是有意的行为,你可以做的是定义一个标题()string
方法,让它返回字符串。
Using golang html/template (same behavior with text/template). If I have a struct with a member that is of an interface type, I cannot access members of the underlying type (specifically trying to access fields that are on a struct that implements interface InnerInterface but is return via the InnerInterface interface type, not the struct type).
http://play.golang.org/p/ZH8wSK83oM
package main import "fmt" import "os" import "html/template" type InnerInterface interface{ InnerSomeMethod() } type MyInnerStruct struct { Title string } func (mis MyInnerStruct)InnerSomeMethod() { fmt.Println("Just to show we're satisfying the interface") } type MyOuterStruct struct { Inner InnerInterface } func main() { fmt.Println("Starting") arg := MyOuterStruct{Inner:MyInnerStruct{Title:"test1"}} err := template.Must(template.New("testtmpl").Parse("{{.Inner.Title}}")).Execute(os.Stdout, arg) if err != nil { panic(err) } }
Changing: type MyOuterStruct struct { Inner InnerInterface } to a totally generic interface, i.e. type MyOuterStruct struct { Inner interface{} } makes it render properly. This leads me to believe that interface{} is treated specially by the rendering engine.
Is there a better way to do this than to use interface{} whenever I want to be able to dynamically evaluate fields like this?
You're correct with saying that interface{} is handled differently by the renderingengine. Only interface{} values are unpacked, interface values that have a method set are not.I suppose the reasoning behind this is that if you have a interface type, you specifically limit the type to the method set. Therefore, you don't want the template engine trying to access members that may lie behind that interface.
The 'problem' is caused by the function indirect in exec.go:
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) { for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() { if v.IsNil() { return v, true } if v.Kind() == reflect.Interface && v.NumMethod() > 0 { break } } return v, false }
This method is called to get to the deepest value of a reflected value.Suppose you have a pointer on a pointer on a pointer, this function will get return thelast of these. The same goes for interface values. The crux is that as soon as a interface value has more than 0 methods, the indirection stops there. Exactly thebehaviour you're describing.
As this seems to be intended behaviour, what you can do is to define a Title() string method in your interface and let it return the string.
这篇关于模板不会将接口类型的字段计算为基础类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!