接口中存在无关的方法会破坏文本/模板吗?

huangapple go评论91阅读模式
英文:

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(&quot;test&quot;).Parse(&quot;{{ .Something.Name }}\n&quot;))
	
	// This works fine.
	if err := t.Execute(os.Stdout, FooContext{Person{&quot;Timmy&quot;}}); err != nil {
		fmt.Printf(&quot;Error: %s\n&quot;, 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{&quot;Timmy&quot;}}); err != nil {
		fmt.Printf(&quot;Error: %s\n&quot;, 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 &quot;test&quot; at &lt;.Something.Name&gt;: can&#39;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&#39;s final arg.
325			// If the object has type interface{}, dig down one level to the thing inside.
326			if value.Kind() == reflect.Interface &amp;&amp; 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.

huangapple
  • 本文由 发表于 2013年10月31日 05:31:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/19694187.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定