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

Why the IO.Writer doesn't fill the receiver?

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

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

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

template.Execute() expects an io.Writer。输出的 Write() 方法可能会被调用多次,而您的 stringer.Write() 方法总是会丢弃之前写入的数据。您可以通过始终将新数据连接到旧数据来修复它,如下所示:

*s = *s + stringer(b)

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

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

bytes.NewBuffer(nil)

您不需要创建自己的 stringer 类型。在 Go Playground.

上尝试修改后的程序