Golang ioutil.ReadAll бесконечный цикл - PullRequest
0 голосов
/ 04 мая 2020

Я новичок в Golang.

Я пытаюсь понять, как использовать 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 Playground):

// 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, где они явно должны закрыть тело после прочтения, но я не вижу метода в байтовом ридере, чтобы закрыть это.

Может кто-нибудь помочь мне понять, что происходит в этом случае? Заранее спасибо.

1 Ответ

3 голосов
/ 05 мая 2020

Вы создаете новый bytes.Reader каждый раз, когда вызывается Thing.Read(). ReadAll() будет просто вызывать вашу Thing.Read() функцию каждый раз, получая одни и те же 11 байтов.

Из ваших комментариев я думаю, что вы хотите создать ее только один раз, например, в «конструкторе», откуда вы надеваете Не нужно хранить Body, как оно хранится в Bytes.Reader.

type Thing struct {
    r io.Reader
}

func NewThing(s string) (t Thing) {
    t.r = bytes.NewReader([]byte(s))
    return
}

func (t Thing) Read(dst []byte) (n int, err error) {
    return t.r.Read(dst)
}

Но тогда Thing - это просто оболочка io.Reader, которая не имеет смысла. Вы также можете напрямую использовать io.Reader.

    buf2, err := ioutil.ReadAll(bytes.NewReader([]byte("Hello World")))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...