8

游乐场链接: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)
    }
}

当我渲染一个包含 的模板(通过text/template包){{ .Something.Name }}时,我可以通过Foo不包含任何方法的接口,它工作正常。但是,如果我Bar改为通过界面,我会得到:

executing "test" at <.Something.Name>: can't evaluate field Name in type main.Bar

为什么界面上存在甚至没有使用的不相关方法会影响模板的呈现?

4

1 回答 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 没有字段名称。如果您想在那里使用接口,则需要通过接口中的方法提供数据。

于 2013-10-30T22:59:14.993 回答