Получение сообщения об ошибке «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.

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

wmlhust
источник