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

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

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

问题

我正在尝试测试一个模板生成工具。为了做到这一点,我认为捕获模板执行输出的最简单方法是使用一个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

英文:

I'm trying to test a template generation tool. In order to do this I was thinking that the easiest way to capture the template execution output is to use a io writer and provide it during testing. The issue is that for some reasons the receiver is not "updated" with the template output. Hopefully the code below explains better the issue I'm facing.

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

得分: 2

你的stringer类型只是*string类型的“别名”。在Go中,string是不可变的。你不应该使用stringstring的指针来构建模板的输出,因为你不能修改一个string,你只能创建一个新的(并且丢弃旧的)。

template.Execute()期望一个io.Writer。输出的Write()方法可能会被多次调用,而你的stringer.Write()方法总是丢弃之前写入的数据。你可以通过始终将新数据与旧数据连接起来来修复它,像这样:

*s = *s + stringer(b)

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

一个更好且可立即使用的替代方案是bytes.Buffer。你可以创建一个实现了Writer接口的字节缓冲区,像这样:

bytes.NewBuffer(nil)

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

英文:

Your stringer type is just an "alias" to *string type. string in Go is immutable. You shouldn't use a string or a pointer to a string to build the the output of a template, because you can't modify a string, you can only create a new (and throw away the old one).

template.Execute() expects an io.Writer. The Write() method of the output might be called multiple times, and your stringer.Write() method always throws away data written to it earlier. You could fix it by always concatenating the new data to the old like this:

*s = *s + stringer(b)

But this solution is terribly inefficient (it generates new strings and throws away old ones).

A much better and ready-to-use alternative is bytes.Buffer. You can create a byte buffer which implements the Writer interface like this:

bytes.NewBuffer(nil)

You don't need to create your own stringer type. Try your modified program on Go Playground.

huangapple
  • 本文由 发表于 2015年2月4日 20:28:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/28321399.html
匿名

发表评论

匿名网友

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

确定