Obter a mensagem de erro “bytes.Buffer não implementa io.Writer”

98

Estou tentando fazer com que algum objeto Go implemente io.Writer, mas grava em uma string em vez de um arquivo ou objeto semelhante a um arquivo. Achei bytes.Bufferque funcionaria, uma vez que implementa Write(p []byte). No entanto, quando tento isso:

import "bufio"
import "bytes"

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

Estou tendo o erro a seguir:

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)

Estou confuso, pois claramente implementa a interface. Como faço para resolver esse erro?

Kevin burke
fonte
2
Já me deparei com esse problema pelo menos duas vezes, e pesquisar uma solução no Google foi realmente inútil.
Kevin Burke
11
Observe que a criação de um bufio não é necessária. Basta usar & b como io.Writer
Vivien

Respostas:

153

Passe um ponteiro para o buffer, em vez do próprio buffer:

import "bufio"
import "bytes"

func main() {
    var b bytes.Buffer
    foo := bufio.NewWriter(&b)
}
Kevin burke
fonte
4
Corri para isso e estaria interessado em saber por que isso acontece. Não estou familiarizado com as dicas em Go.
hora de retorno de
1
Obrigado Kevin, este erro simples levou uma hora do meu tempo até que eu pesquisei isso no Google. :)
Nelo Mitranim 16/11/2014
7
@hourback tem a ver com a maneira como a interface é implementada. Na verdade, existem várias maneiras de implementar uma interface em Go. Com receptores de valor ou de ponteiro. Eu acho que essa é uma reviravolta muito peculiar para ir. Se a interface for implementada usando receptores de valor de qualquer maneira, está tudo bem, mas se a interface for implementada usando receptores de ponteiro, você terá que passar um ponteiro para o valor se quiser usar a interface. Faz sentido, uma vez que o gravador precisa alterar o buffer para controlar onde está a cabeça do gravador.
John Leidegren de
23
package main

import "bytes"
import "io"

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

Você não precisa usar "bufio.NewWriter (& b)" para criar um io.Writer. & b é o próprio io.Writer.

aQua
fonte
Esta deve ser a resposta certa. Se você tentar criar um novo gravador fora do buffer, não será capaz de buscar os bytes do buffer diretamente, o que torna as coisas muito mais complicadas.
onetwopunch
8

Apenas use

foo := bufio.NewWriter(&b)

Porque a forma como bytes.Buffer implementa 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, não b Buffer. (Também acho estranho porque podemos chamar um método por uma variável ou seu ponteiro, mas não podemos atribuir um ponteiro a uma variável do tipo não ponteiro.)

Além disso, o prompt do compilador não é claro o suficiente:

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


Algumas idéias, vá usar Passed by value, se passarmos bpara buffio.NewWriter(), em NewWriter (), é um novob (um novo buffer), não o buffer original que definimos, portanto precisamos passar o endereço &b.

Anexe novamente, bytes.Buffer é definido:

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.
}

usando passed by value, a nova estrutura de buffer passada é diferente da variável de buffer de origem.

wmlhust
fonte