【问题标题】:Should my function take channels as input?我的函数应该将通道作为输入吗?
【发布时间】:2021-11-17 00:25:59
【问题描述】:

我正在构建一个管理数据并将数据写入文件的 go 库。我写了一个文件写入器,我可以将数据传递给它,它会通过缓冲写入器将该数据写入文件。这意味着一旦服务关闭,使用该库的服务将不得不调用 close 方法以写入仍在缓冲区中的任何内容。我看到了两种处理方式:

  1. 公开服务可以使用的Close 方法。
  2. 使用频道。如果服务关闭通道,那将关闭库中的缓冲区。我的 lib 函数如下所示:
func (r *Repo) Write(ctx context.Context, data <-chan Data, errCh chan<- error) error {
    for doc := range data {
        err := r.file.Write(ctx, doc)
        if err != nil {
            errCh <- err
        }
    }

    err = r.file.Close(ctx)
    return err
}

我的问题是Write() 签名是否有意义,因为它需要一个接收通道和一个错误发送通道作为输入?我还没有看到类似的例子。也许有更好的组织方式?

【问题讨论】:

  • 发布并期望使用Close() 方法很常见。我不明白为什么你应该让你的 API 使用通道,只是因为你有一些清理工作要做。

标签: go


【解决方案1】:

选项 1。即使用 Close 函数更有意义,尤其是在查看做事方式时。

如果没有通道也可以完成,使用通道也会使事情变得复杂。 就像Write 的实现有一个持续读取数据的for 循环。

    for doc := range data {
        err := r.file.Write(ctx, doc)
        if err != nil {
            errCh <- err
        }
    }

这意味着任何调用此 write 函数的人都会被阻塞,如果需要非阻塞行为,则需要将其调用到 goroutine 中。

另外还有一个简单的写签名,例如:
func (r *Repo) Write(data Data) error
看起来更干净,并且上下文可以作为Repo 初始化的一部分,如果每次调用函数时都没有改变的话。

【讨论】:

  • 是的,谢谢。我想我想太多了。我会坚持最简单的。有道理。
  • 我过去也做过类似的过度思考。我从查看库中学到的一个教训是,它们应该足够简单,以便客户可以在需要时围绕它构建复杂的逻辑。
猜你喜欢
  • 1970-01-01
  • 2021-08-26
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-20
相关资源
最近更新 更多