你正在使用的Go版本是什么( go version
)?
$ go version
go version go1.14.15 linux/amd64
这个问题在最新版本的发布中是否重现?
是的。
你正在使用什么操作系统和处理器架构( go env
)?
go env
输出
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/cyphar/.cache/go-build"
GOENV="/home/cyphar/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/cyphar/.local"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib64/go/1.14"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib64/go/1.14/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build440126677=/tmp/go-build -gno-record-gcc-switches"
你做了什么?
https://play.golang.org/p/6dFx2mL7f5r
package main
import (
"fmt"
"io"
"io/ioutil"
)
type dummyReader struct {}
func (r dummyReader) Read(p []byte) (n int, err error) {
return 0, io.EOF
}
type dummyWriteTo struct {
dummyReader
}
func (r dummyWriteTo) WriteTo(w io.Writer) (n int64, err error) {
return 0, io.EOF
}
func main() {
n, err := io.Copy(ioutil.Discard, dummyReader{})
fmt.Printf("io.Copy using io.Reader -- n=%v, err=%v\n", n, err)
n, err = io.Copy(ioutil.Discard, dummyWriteTo{})
fmt.Printf("io.Copy using io.WriterTo -- n=%v, err=%v\n", n, err)
}
主要问题是,如果你有一个实现了返回 io.EOF
的 io.Reader
,那么 io.Copy
会盲目地转发这个错误。 klauspost/pgzip#38 是一个犯了这个错误的例子,我在 opencontainers/umoci#360 中遇到了这个问题。
同样的事情也发生在从 ReadFrom
返回 io.EOF
(这有点奇怪,但如果你不在 io.Copy
的实现中使用 io.ReaderFrom
,你可能会不小心这样做)。
看起来这要么是:
- 一个文档问题,因为据我所知,
io.WriterTo
和io.ReaderFrom
的文档没有提到不应该从这些方法中返回io.EOF
。措辞上确实暗示了不应该返回io.EOF
,但我认为这应该更加明确,因为任何不使用io.Copy
内部实现的WriteTo
实现都必须显式处理这个问题,并应该被警告这种情况。 - 是
io.Copy
(以及可能与io.WriterTo
和io.ReaderFrom
相关的相关 stdlib 用户)的一个bug,因为当它由io.EOF
返回时, x20n20会被处理。
你期望看到什么?
x22b22
或者文档提到不应该从 x23n23 返回 x24n24。
你看到了什么?
x25b25
5条答案
按热度按时间rta7y2nd1#
我认为这是一个文档问题。我无法看到任何理由为什么
WriteTo
或ReadFrom
应该返回io.EOF
。xhv8bpkk2#
@ianlancetaylor 我做了一份PR,你能帮忙看一下吗?谢谢!
n3h0vuf23#
https://golang.org/cl/294709提到了这个问题:
fix: io/copy document. fix #44411
kxe2p93d4#
我无法看到任何理由为什么WriteTo或ReadFrom应该返回io.EOF。如果你不使用
io.Copy
内部,而是使用其他一些I/O方法,那么你可能会意外地得到这个结果。但是,如果语义基本上是“更高效的io.Copy
”,那么我同意它永远不应该返回io.EOF
。谢谢。z2acfund5#
https://golang.org/cl/294769提到了这个问题:
io: unify EOF documentation for ReadFrom and WriteTo