给定以下函数

func jsonBodyReader(config Config, r *http.Request) (io.Reader, error) {
    bodyReader := io.LimitReader(r.Body, config.Reports.Max.Body)
    // defer r.Body.Close()

    gzipReader, err := gzip.NewReader(bodyReader)
    if err != nil {
        return nil, err
    }
    // defer gzipReader.Close()

    return io.LimitReader(gzipReader, config.Reports.Max.Json), nil
}

处理r.BodygzipReader的延迟收盘的最佳方式是什么?

是否真的需要总是返回所有中间资源/流/读取器才能在父函数中延迟/关闭它们?

另一示例

func save(target string, reader io.Reader) (io.Reader, *os.File, error) {
    file, err := os.Create(target)
    if err != nil {
        return reader, nil, err
    }
    /// defer file.Close()

    return io.TeeReader(reader, file), file, nil
}

在这种情况下,我必须返回os.File,才能在父级中调用file.Close().

我发现了这个相关的问题:How to defer resource cleanup when that resource outlives the scope of the surrounding function?不幸的是,建议的解决方案对于我的用例来说仍然很尴尬.

推荐答案

如果函数的调用者必须从函数打开或修改的文件或流中读取,则不能在该函数中延迟关闭它.当函数返回时,流或文件将被关闭,try 从中读取的调用者失败.

在第一个示例中,您有两个受限的读取器,一个用于限制正文,另一个用于限制解压缩后的json.您可以这样做:

func jsonBodyReader(config Config, r *http.Request) (io.ReadCloser, error) {
    bodyReader := io.LimitReader(r.Body, config.Reports.Max.Body)
    gzipReader, err := gzip.NewReader(bodyReader)
    if err != nil {
        return nil, err
    }
    return readerCloser{
       Reader:io.LimitReader(gzipReader, config.Reports.Max.Json),
       cl: r.Body,
    }, nil
}

哪里

type readerCloser struct {
   io.Reader
   cl io.Closer
}

func (r *readerCloser) Close() error { return r.cl.Close() }

readerCloser类型允许您返回调用方可以读取并关闭的ReaderCloser,这将关闭源流.

Go相关问答推荐

Golang regexpp:获取带有右括号的单词

gorm插入不支持的数据

如何在使用中介资源时处理函数中的`defer`

如何在jsonrpc服务器的服务器端捕获错误?

如何使用 AWS sdk 在 Go 中正确解组 PartiQL 查询的结果?

Go安装成功但没有输出简单的Hello World

转到 bufio.Writer、gzip.Writer 并上传到内存中的 AWS S3

如何根据地址和大小打印字符串

带有前导零的整数参数被 flag.IntVar 解析为八进制

Go 中的 YAML 自定义标签

如何在 Golang http.Request 对象中读取自定义 ajaxParams

Go 信号处理程序不处理终端窗口关闭

如何将 npm 安装进度条通过管道传输到终端?

如何使用 Go 获取 X11 中的窗口列表

为什么此代码在运行命令 error="exec: not started" 时出现错误?

如何在测试中使用自定义标志(使用`testify/suite`)

递归数据 struct 解组在 Go Lang Protobuf 中给出错误无法解析无效的线格式数据

使用 xml.Name 将 xml 解组为 [] struct

如何扩充 ResponseWriter 的 Header() 返回的 map

Golang 与 Cassandra db 使用 docker-compose:cannot connect (gocql)