5

使用 golang html/template(与 相同的行为text/template)。如果我有一个具有接口类型成员的结构,则我无法访问基础类型的成员(特别是尝试访问实现接口InnerInterface但通过InnerInterface接口类型而不是结构类型返回的结构上的字段) .

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

}

更改:type MyOuterStruct struct { Inner InnerInterface }到一个完全通用的界面,即使type MyOuterStruct struct { Inner interface{} }其正确呈现。这使我相信interface{}渲染引擎会对其进行特殊处理。

interface{}有没有比在我希望能够动态评估这样的字段时使用更好的方法来做到这一点?

4

1 回答 1

5

你说interface{}渲染引擎处理方式不同是正确的。只有interface{}值被解包,具有方法集的接口值不被解包。我想这背后的原因是,如果你有一个接口类型,你会专门将类型限制为方法集。因此,您不希望模板引擎尝试访问可能位于该接口后面的成员。

“问题”是由以下功能引起indirectexec.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
}

调用此方法以获取反射值的最深值。假设你有一个指针上的指针,这个函数将返回其中的最后一个。接口值也是如此。关键是,一旦接口值具有超过 0 个方法,间接就停止在那里。正是您所描述的行为。

由于这似乎是预期的行为,您可以做的是Title() string 在您的界面中定义一个方法并让它返回字符串。

于 2013-10-24T01:24:46.640 回答