The template will not evaluate fields that are an interface type as a base type.

Using golang html/template (same behavior with text/template ). If I have a structure with a member that has an interface type, I cannot access the elements of the base type (in particular, it tries to access the fields that are in the structure that implements the InnerInterface interface, but returns via the InnerInterface interface InnerInterface , not type of structure).

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) } } 

Change: type MyOuterStruct struct { Inner InnerInterface } to a completely common interface, ie type MyOuterStruct struct { Inner interface{} } makes it correct. This makes me think that interface{} handled specifically by the rendering engine.

Is there a better way to do this than using interface{} whenever I want to dynamically evaluate such fields?

+4
struct interface go field
source share
1 answer

You are right in saying that interface{} handled differently by the rendering engine. Only interface{} values ​​are unpacked, interface values ​​that have a set of methods are missing. I suggest that the argument for this is that if you have an interface type, you specifically limit the type to a set of methods. Therefore, you do not want the template engine to try to access the elements that may lie behind this interface.

The "problem" is caused by the indirect function 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 the deepest value of the reflected value. Suppose you have a pointer to a pointer to a pointer, this function will return the last one. The same goes for interface values. The bottom line is that as soon as an interface value has more than 0 methods, that is, vice versa. It is the behavior that you describe.

Since this seems to be intended for behavior, you can define a Title() string method in your interface and let it return a string.

+4
source share

All Articles