【问题标题】:Implement io.WriterTo with JSON使用 JSON 实现 io.WriterTo
【发布时间】:2022-12-30 23:56:14
【问题描述】:

我最近发现了这个很酷的界面,io.WriterTo

https://godocs.io/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 之前在内存中复制对象。是不是可以直接写,还知道写了多少字节?

【问题讨论】:

  • 在您的示例中,您只需委托bytes.Buffer。就适用性而言,我认为此接口允许您实现自定义方式来编排写入流程。示例:实现缓存并不总是需要计算编码。

标签: json go interface


【解决方案1】:

要直接写入,请创建一个 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
}

Run an example on the the Go PlayGround

【讨论】:

  • 这是一个很酷的例子。为了获得更高质量的答案,您介意描述此代码的适用性。
【解决方案2】:

是不是可以直接写,还知道写了多少字节?

巧的是书上的习题7.2是什么Go 编程语言是关于。练习包括使用签名实现函数:

func CountingWriter(w io.Writer) (io.Writer, *int64)

返回的指向int64 的指针必须随时包含写入返回的io.Writer 的字节数。本质上,返回的io.Writer 是一个decorator,因为它通过更新字节计数器增强了初始io.Writer 的功能。

让我们创建类型writerFunc,它与io.WriterWrite的唯一方法具有相同的参数化:

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,这个函数的调用者最终会收到。

【讨论】:

    猜你喜欢
    • 2021-11-29
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多