为什么IO.Writer没有填充接收器?

时间:2015-02-04 12:28:03

标签: go

我正在尝试测试模板生成工具。为了做到这一点,我认为捕获模板执行输出的最简单方法是使用io writer并在测试期间提供它。问题在于,由于某些原因,接收器未被更新"使用模板输出。希望下面的代码更好地解释了我面临的问题。

package main

import "fmt"
import "text/template"

type Company struct{
    Name string
} 

type Companies []Company

func main() {
    s := new(stringer)

    v := Companies{Company{Name:"Sony"}}
    tmp :=  template.Must(template.New("main").Parse(src))
    if err := tmp.Execute(s, v); err !=nil{
        panic(err)
    }
    if *s != "this is the header template"{
        fmt.Println("expected: \"this is the header template\" received: ", *s) 
    }else{
      fmt.Println("s is %v", *s)
    }
}

type stringer string
func (s *stringer)Write(b []byte)(int, error){
    *s = stringer(b)
    return len(b), nil
}

var src = `
 this is the header template
    {{range .}}

    {{.Name}}

    {{end}}
`

http://play.golang.org/p/y4zWgyd5G1

1 个答案:

答案 0 :(得分:2)

您的stringer类型只是*string类型的“别名”。 Go中的string是不可变的。您不应该使用string或指向string的指针来构建模板的输出,因为您无法修改string,您只能创建一个新的(扔掉旧的。)

template.Execute()需要io.Writer。可能会多次调用输出的Write()方法,并且您的stringer.Write()方法始终会丢弃先前写入的数据。您可以通过始终将新数据连接到旧数据来解决此问题:

*s = *s + stringer(b)

但是这个解决方案非常低效(它会生成新的string并抛弃旧的)。

更好且易于使用的替代方案是bytes.Buffer。您可以创建一个实现Writer接口的字节缓冲区,如下所示:

bytes.NewBuffer(nil)

您无需创建自己的stringer类型。在Go Playground上尝试修改后的程序。