Получение сообщения об ошибке «bytes.Buffer не реализует io.Writer»


101

Я пытаюсь реализовать io.Writer в каком-либо объекте Go, но записывает его в строку, а не в файл или файловый объект. Думал bytes.Bufferзаработает раз уж реализует Write(p []byte). Однако, когда я пытаюсь это сделать:

import "bufio"
import "bytes"

func main() {
    var b bytes.Buffer
    foo := bufio.NewWriter(b)
}

Я получаю следующую ошибку:

cannot use b (type bytes.Buffer) as type io.Writer in function argument:
bytes.Buffer does not implement io.Writer (Write method has pointer receiver)

Я смущен, так как он четко реализует интерфейс. Как мне исправить эту ошибку?


2
Я сталкивался с этой проблемой как минимум дважды, и поиск решения в Google оказался бесполезным.
— Кевин Берк

11
Обратите внимание, что создание bufio не требуется. Просто используйте & b как io.Writer
— Вивьен

Ответы:


156

Передайте указатель на буфер вместо самого буфера:

import "bufio"
import "bytes"

func main() {
    var b bytes.Buffer
    foo := bufio.NewWriter(&b)
}

4
Я столкнулся с этим, и мне было бы интересно узнать, почему это так. Я довольно плохо знаком с указателями в Go.
— Hourback

2
Спасибо, Кевин, эта простая ошибка заняла у меня час времени, пока я не погуглил. :)
— Нело Митраним

8
@hourback это связано со способом реализации интерфейса. На самом деле есть способы реализовать интерфейс в Go. Либо с получателями значения или указателя. Я думаю, что это действительно своеобразный поворот в Go. Если интерфейс реализован с использованием приемников значений, в любом случае это нормально, но если интерфейс реализован с использованием приемников указателей, вам необходимо передать указатель на значение, если вы собираетесь использовать интерфейс. Это имеет смысл, поскольку писатель должен видоизменить буфер, чтобы отслеживать, где он находится.
— Джон Лейдегрен

24
package main

import "bytes"
import "io"

func main() {
    var b bytes.Buffer
    _ = io.Writer(&b)
}

Вам не нужно использовать bufio.NewWriter (& b) для создания io.Writer. & b - это сам io.Writer.


Это должен быть правильный ответ. Если вы попытаетесь создать новый модуль записи из буфера, вы не сможете напрямую получить байты из буфера, что значительно усложняет задачу.
— onetwopunch

8

Просто используйте

foo := bufio.NewWriter(&b)

Поскольку способ, которым bytes.Buffer реализует io.Writer, является

func (b *Buffer) Write(p []byte) (n int, err error) {
    ...
}
// io.Writer definition
type Writer interface {
    Write(p []byte) (n int, err error)
}

Это b *Bufferне так b Buffer. (Я также думаю, что это странно, потому что мы можем вызывать метод с помощью переменной или ее указателя, но мы не можем назначить указатель на переменную типа без указателя.)

Кроме того, подсказка компилятора недостаточно ясна:

bytes.Buffer does not implement io.Writer (Write method has pointer receiver)


Некоторые идеи, использовать Go Passed by value, если мы переходим bк buffio.NewWriter(), в NewWriter (), это новый b(новый буфер), а не исходный буфер мы определили, поэтому нужно передать адрес &b.

Снова добавить, bytes.Buffer определен:

type Buffer struct {
    buf       []byte   // contents are the bytes buf[off : len(buf)]
    off       int      // read at &buf[off], write at &buf[len(buf)]
    bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
    lastRead  readOp   // last read operation, so that Unread* can work correctly.
}

при использовании passed by value, переданная новая структура буфера отличается от переменной исходного буфера.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.