英文:
Implement io.WriterTo with JSON
问题
我最近发现了这个很酷的接口,io.WriterTo
:
我想为一些 JSON 对象实现它。我已经能够做到这一点:
package calendar
import (
"bytes"
"encoding/json"
"io"
)
type date struct {
Month int
Day int
}
func (d date) WriteTo(w io.Writer) (int64, error) {
buf := new(bytes.Buffer)
err := json.NewEncoder(buf).Encode(d)
if err != nil {
return 0, err
}
return buf.WriteTo(w)
}
但我认为这不是理想的,因为它在发送给 Writer 之前会在内存中复制对象。有没有可能直接写入,同时知道写入了多少字节?
英文:
I found this cool interface recently, io.WriterTo
:
I would like to implement it for some JSON objects. I was able to make this:
package calendar
import (
"bytes"
"encoding/json"
"io"
)
type date struct {
Month int
Day int
}
func (d date) WriteTo(w io.Writer) (int64, error) {
buf := new(bytes.Buffer)
err := json.NewEncoder(buf).Encode(d)
if err != nil {
return 0, err
}
return buf.WriteTo(w)
}
But I think it's not ideal, as it makes a copy of the object in memory, before sending to the Writer. Is it possible to write directly, but also know how many bytes were written?
答案1
得分: 2
直接编写一个io.Writer包装器来计算写入的字节数:
type countingWriter struct {
n int64
w io.Writer
}
func (cw *countingWriter) Write(p []byte) (int, error) {
n, err := cw.w.Write(p)
cw.n += int64(n)
return n, err
}
将WriteTo方法更改为将数据编码到一个包装了参数的写入器中。完成后返回字节数和错误。
func (d date) WriteTo(w io.Writer) (int64, error) {
cw := &countingWriter{w: w}
err := json.NewEncoder(cw).Encode(d)
return cw.n, err
}
英文:
To write directly, create an io.Writer wrapper that counts the bytes written:
type countingWriter struct {
n int64
w io.Writer
}
func (cw *countingWriter) Write(p []byte) (int, error) {
n, err := cw.w.Write(p)
cw.n += int64(n)
return n, err
}
Change the WriteTo method to encode to a writer where the writer is the wrapper on the argument. Return the count of bytes and error when done.
func (d date) WriteTo(w io.Writer) (int64, error) {
cw := &countingWriter{w: w}
err := json.NewEncoder(cw).Encode(d)
return cw.n, err
}
答案2
得分: 0
是否可以直接写入,并且知道写入了多少字节呢?
巧合的是,这正是《Go程序设计语言》一书中的练习7.2所涉及的内容。该练习要求实现一个具有以下签名的函数:
func CountingWriter(w io.Writer) (io.Writer, *int64)
返回的int64
指针必须始终包含写入返回的io.Writer
的字节数。本质上,返回的io.Writer
是一个装饰器,它通过更新字节计数器来增强初始io.Writer
的功能。
首先,让我们创建类型writerFunc
,它具有与io.Writer
的唯一方法Write
相同的参数化:
type writerFunc func([]byte) (int, error)
然后,在writerFunc
上定义Write(p []byte) (int, error)
方法:
func (wf writerFunc) Write(p []byte) (int, error) {
return wf(p)
}
这样,writerFunc
满足io.Writer
并且可以将任何func([]byte) (int, error)
适配为io.Writer
- 也就是说,我们可以在需要io.Writer
的地方将func([]byte) (int, error)
包装在writerFunc
中。
最后,我们来看一下我们要找的CountingWriter
装饰函数:
func CountingWriter(w io.Writer) (io.Writer, *int64) {
count := new(int64)
writeAndCount := func(data []byte) (int, error) {
bytes, err := w.Write(data)
*count += int64(bytes)
return bytes, err
}
return writerFunc(writeAndCount), count
}
请注意最后的return
语句:闭包writeAndCount
被包装在writerFunc
中。这是因为闭包的类型也是func([]byte) (int, error)
。正如我们上面所看到的,writerFunc
满足io.Writer
,这样调用此函数的调用者最终就会得到它。
英文:
> Is it possible to write directly, but also know how many bytes were written?
Coincidentally, it is what exercise 7.2 of the book The Go Programming Language is about. The exercise consists of implementing a function with the signature:
func CountingWriter(w io.Writer) (io.Writer, *int64)
The returned pointer to int64
must contain at any moment the number of bytes written to the returned io.Writer
. Essentially, the returned io.Writer
is a decorator as it enhances the functionality of the initial io.Writer
by updating a byte counter.
First, let's create the type writerFunc
, which has the same parametrization as the only method of io.Writer
, Write
:
type writerFunc func([]byte) (int, error)
Then, define the method Write(p []byte) (int, error)
on writerFunc
:
func (wf writerFunc) Write(p []byte) (int, error) {
return wf(p)
}
This way, writerFunc
satisfies io.Writer
and serves as an adapter for any func([]byte) (int, error)
into an io.Writer
– i.e., we can wrap a func([]byte) (int, error)
in a writerFunc
whenever an io.Writer
is required.
Finally, the CountingWriter
decorating function we are looking for:
func CountingWriter(w io.Writer) (io.Writer, *int64) {
count := new(int64)
writeAndCount := func(data []byte) (int, error) {
bytes, err := w.Write(data)
*count += int64(bytes)
return bytes, err
}
return writerFunc(writeAndCount), count
}
Note the last return
statement: the closure writeAndCount
is wrapped in a writerFunc
. This works because the closure's type is func([]byte) (int, error)
as well. As we have seen above, writerFunc
satisfies io.Writer
, which the caller of this function eventually receives.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论