Uzyskiwanie komunikatu o błędzie „bytes.Buffer nie implementuje io.Writer”

100

Próbuję mieć jakiś obiekt Go zaimplementować io.Writer, ale zapisuje do ciągu zamiast do pliku lub obiektu podobnego do pliku. Pomyślałem, że bytes.Bufferbędzie działać, ponieważ wdraża Write(p []byte). Jednak kiedy próbuję tego:

import "bufio"
import "bytes"

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

Otrzymuję następujący błąd:

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)

Jestem zdezorientowany, ponieważ wyraźnie implementuje interfejs. Jak rozwiązać ten błąd?

Kevin Burke
źródło
2
Natknąłem się na ten problem co najmniej dwa razy, a szukanie rozwiązania w Google było naprawdę nieprzydatne.
Kevin Burke
11
Pamiętaj, że tworzenie bufio nie jest konieczne. Po prostu użyj & b jako io.Writer
Vivien

Odpowiedzi:

156

Przekaż wskaźnik do bufora zamiast do samego bufora:

import "bufio"
import "bytes"

func main() {
    var b bytes.Buffer
    foo := bufio.NewWriter(&b)
}
Kevin Burke
źródło
4
Wpadłem na to i chciałbym dowiedzieć się, dlaczego tak jest. Nie znam wskazówek w Go.
godzina powrotu
2
Dzięki Kevin, ten prosty błąd zajął mi godzinę, zanim go wyszukałem. :)
Nelo Mitranim
7
@hourback ma to związek ze sposobem implementacji interfejsu. W rzeczywistości istnieje wiele sposobów implementacji interfejsu w Go. Albo z odbiornikami wartości lub wskaźnika. Myślę, że to naprawdę osobliwy zwrot akcji w Go. Jeśli interfejs jest zaimplementowany przy użyciu odbiorników wartości, którykolwiek z tych sposobów jest w porządku, ale jeśli interfejs jest zaimplementowany przy użyciu odbiorników wskaźników, musisz przekazać wskaźnik do wartości, jeśli zamierzasz używać interfejsu. Ma to sens, ponieważ autor musi zmutować bufor, aby śledzić, gdzie jest jego głowa.
John Leidegren,
24
package main

import "bytes"
import "io"

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

Nie musisz używać „bufio.NewWriter (& b)”, aby utworzyć io.Writer. & b jest samym io.Writer.

wodny
źródło
To powinna być właściwa odpowiedź. Jeśli spróbujesz utworzyć nowy program zapisujący z bufora, nie będziesz w stanie bezpośrednio pobrać bajtów bufora, co znacznie komplikuje sprawę.
onetwopunch
8

Po prostu użyj

foo := bufio.NewWriter(&b)

Ponieważ sposób bytes.Buffer implementuje io.Writer jest

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

To b *Buffernie jest b Buffer. (Myślę też, że to dziwne, ponieważ możemy wywołać metodę za pomocą zmiennej lub jej wskaźnika, ale nie możemy przypisać wskaźnika do zmiennej typu niebędącego wskaźnikiem).

Poza tym zachęta kompilatora nie jest wystarczająco jasna:

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


Niektóre pomysły, używają Go Passed by value, jeśli przejdziemy bdo buffio.NewWriter(), w NewWriter (), jest to nowy b(nowy bufor), a nie oryginalny bufor, który zdefiniowaliśmy, dlatego musimy przekazać adres &b.

Dodaj ponownie, bajty. Zdefiniowany jest bufor:

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

using passed by value, przekazana nowa struktura bufora różni się od zmiennej bufora pochodzenia.

wmlhust
źródło