Golang ioutil.ReadAll无限循环

Golang ioutil.ReadAll无限循环,go,Go,我是刚来戈朗的 我试图理解如何使用ioutil.ReadAll非HTTP响应。根据源代码和文档: // ReadAll reads from r until an error or EOF and returns the data it read. // A successful call returns err == nil, not err == EOF. Because ReadAll is // defined to read from src until EOF, it does no

我是刚来戈朗的

我试图理解如何使用ioutil.ReadAll非HTTP响应。根据源代码和文档:

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
func ReadAll(r io.Reader) ([]byte, error) {
    return readAll(r, bytes.MinRead)
}
在本例中,我还实现了一个io.Reader,它也是在Go游乐场上实现的:

// go version go1.13.5 darwin/amd64

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
)

// Thing contains a body
type Thing struct {
    Body []byte
}

// Read reads from body into p
func (t Thing) Read(dst []byte) (n int, err error) {
    // Note: bytes.Reader does return io.EOF
    // https://golang.org/src/bytes/reader.go?s=1154:1204#L30
    reader := bytes.NewReader(t.Body)
    return reader.Read(dst)
}

func main() {
    fmt.Println("Testing bytes")

    thing := new(Thing)
    thing.Body = []byte("Hello World")

    fmt.Println("thing.Body:", string(thing.Body))

    // This works
    buf := make([]byte, len(thing.Body))
    n, err := thing.Read(buf)
    fmt.Println("Amount read:", n)
    if err != nil {
        fmt.Println("Error: ", err)
    }
    fmt.Println("buf:", string(buf))

    // ReadAll runs forever....why?
    buf2, err := ioutil.ReadAll(thing)
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Println("buf2:", buf2)

}
在上面,Read实现工作得很好。它只是调用bytes.NewReader并从中读取。然而,当在结构上使用ioutil.ReadAll时,它会永远超时运行,我不明白为什么。起初,我认为其中可能没有EOF,但字节读取器会在此处返回io.EOF:

// Read implements the io.Reader interface.
func (r *Reader) Read(b []byte) (n int, err error) {
    if r.i >= int64(len(r.s)) {
        return 0, io.EOF
    }
    r.prevRune = -1
    n = copy(b, r.s[r.i:])
    r.i += int64(n)
    return
}
我在http响应体上也看到过这种方法的其他实现,它们在读取后必须显式地关闭响应体,但我没有在字节读取器上看到任何方法来关闭响应体

有人能帮我理解这件事吗?提前感谢。

您正在创建一个新的字节。每次都调用Read。ReadAll将继续调用你的东西。每次读取函数都会得到相同的11个字节

从您的评论中,我认为您只想创建一次,例如,在构造函数中,您不需要像存储在Bytes.Reader中那样存储Body

但那个东西只是一个并没有目的的io.Reader的包装。你也可以直接使用“io.Reader”

    buf2, err := ioutil.ReadAll(bytes.NewReader([]byte("Hello World")))

读是写来读的东西。身体反复无休止地读。Thing.Read的预期功能是什么?Thing.Read将Thing.Body读入dst[]字节。ioutil.ReadAllthing应该返回Thing.Body的内容…每次对Read的调用都会实例化一个新的bytes.Reader,这意味着每次调用都会从一开始就重新开始读取。Read实现必须在流的末尾返回io.EOF。如果您的目标是在Thing.Body中的字节上创建io.Reader,那么按照bytes.Reader.Read中的代码进行操作,您可以忽略预运行的内容。@CeriseLimón感谢您的评论,但我仍然不理解为什么原始实现不起作用。我确实是这样做的:n=copydst,t.Body返回n,io.EOF,但这应该由bytes.NewReader的io.Reader实现来处理。
    buf2, err := ioutil.ReadAll(bytes.NewReader([]byte("Hello World")))