在Go语言中如何将一个写入器(writer)包装成一个读取器(reader)?

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

Wrapping a writer in a reader in Go?

问题

我正在尝试在Go中编写一个生成XML并返回读取器的函数。然而,XML编码器似乎需要一个写入器来写入,我不太确定如何将写入器的输出导入到我想要返回的读取器中。

我尝试了以下代码:

func (i *Item) ToRss() io.Reader {
  reader, writer := io.Pipe()
  enc := xml.NewEncoder(writer)
  enc.Indent("  ", "   ")
  enc.Encode(i)
  return reader
}

但是当我运行以下代码时,出现致命错误:

r := a.ToRss()
buf := new(bytes.Buffer)
buf.ReadFrom(r)
s := buf.String()
fmt.Println(s)

致命错误:所有的goroutine都处于休眠状态 - 死锁!

最终,我想将读取器导入到HTTP请求的输出中。我应该只返回一个[]byte吗?还是有一种好的方法可以缓冲输出,以便客户端可以使用读取器?

英文:

I'm trying to write a function in Go which generates XML and returns a reader for it. However, the XML encoder seems to take a writer to write to and I'm not quite sure how to pipe the output of the writer to the reader I want to return.

I tried this:

func (i *Item) ToRss() io.Reader {                                                     
  reader, writer := io.Pipe()                                                             
  enc := xml.NewEncoder(writer)                                                           
  enc.Indent("  ", "   ")                                                                 
  enc.Encode(i)                                                                           
  return reader                                                                           
}

But when I run the following I get a fatal error:

  r := a.ToRss()
  buf := new(bytes.Buffer)
  buf.ReadFrom(r)
  s := buf.String()
  fmt.Println(s)

> fatal error: all goroutines are asleep - deadlock!

Eventually I'd like to pipe the reader to the output of an HTTP request. Should I just return a []byte? Or is there a nice way to buffer the output so the client can use the reader?

答案1

得分: 3

一个管道不进行内部缓冲。它在读取或写入时会阻塞,直到对应的写入或读取被调用。

在ToRss函数中,你应该使用一个bytes.Buffer,并将其作为你的读取器返回:

func ToRss() io.Reader {
    buf := &bytes.Buffer{}
    io.WriteString(buf, "foo")
    return buf
}

Playground链接

另外,你可以启动一个新的goroutine来向管道写入数据,并将其返回以供主goroutine读取。这种方法可以避免不必要的缓冲,但会引入另一个goroutine。

func ToRss() io.Reader {
    reader, writer := io.Pipe()
    go func() {
        io.WriteString(writer, "foo")
        writer.Close()
    }()
    return reader
}

Playground链接

英文:

A pipe does no internal buffering. It blocks on read or write until a corresponding write or read is called.

You should use a bytes.Buffer inside ToRss and return it as your reader:

func ToRss() io.Reader {
	buf := &bytes.Buffer{}
	io.WriteString(buf, "foo")
	return buf
} 

Playground link

Alternatively you could start a new goroutine to write to the pipe and return it to be read from on the main goroutine. This method will avoid unnecessary buffering, but does introduce another goroutine.

func ToRss() io.Reader {
   reader, writer := io.Pipe()
   go func() {
      io.WriteString(writer, "foo")
	  writer.Close()
   }()
   return reader
}

Playground Link

huangapple
  • 本文由 发表于 2015年4月18日 09:31:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/29711898.html
匿名

发表评论

匿名网友

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

确定