L'obtention du message d'erreur «bytes.Buffer n'implémente pas io.Writer»

98

J'essaie d'avoir un objet Go implémente io.Writer, mais écrit dans une chaîne au lieu d'un fichier ou d'un objet semblable à un fichier. Je pensais que bytes.Buffercela fonctionnerait car il implémente Write(p []byte). Cependant, quand j'essaye ceci:

import "bufio"
import "bytes"

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

J'obtiens l'erreur suivante:

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)

Je suis confus, car il implémente clairement l'interface. Comment résoudre cette erreur?

Kevin Burke
la source
2
J'ai rencontré ce problème au moins deux fois, et chercher une solution sur Google n'a vraiment pas été utile.
Kevin Burke
11
Notez que la création d'un bufio n'est pas nécessaire. Utilisez simplement & b comme un io.Writer
Vivien

Réponses:

153

Passez un pointeur vers le tampon, au lieu du tampon lui-même:

import "bufio"
import "bytes"

func main() {
    var b bytes.Buffer
    foo := bufio.NewWriter(&b)
}
Kevin Burke
la source
4
Je suis tombé sur ceci et serais intéressé à savoir pourquoi c'est le cas. Je ne connais pas vraiment les pointeurs dans Go.
heure de retour
1
Merci Kevin, cette simple erreur a pris une heure de mon temps jusqu'à ce que je google ceci. :)
Nelo Mitranim
7
@hourback cela a à voir avec la façon dont l'interface est implémentée. Il existe en fait des moyens d'implémenter une interface dans Go. Soit avec des récepteurs de valeur ou de pointeur. Je pense que c'est une tournure vraiment particulière à Go. Si l'interface est implémentée à l'aide de récepteurs de valeur dans les deux cas, c'est OK, mais si l'interface est implémentée à l'aide de récepteurs de pointeur, vous devez passer un pointeur vers la valeur si vous avez l'intention d'utiliser l'interface. Cela a du sens puisque l'écrivain doit faire muter le tampon pour garder une trace de l'endroit où il se trouve.
John Leidegren
23
package main

import "bytes"
import "io"

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

Vous n'avez pas besoin d'utiliser "bufio.NewWriter (& b)" pour créer un io.Writer. & b est un io.Writer lui-même.

aqua
la source
Cela devrait être la bonne réponse. Si vous essayez de créer un nouvel enregistreur à partir du tampon, vous ne pourrez pas récupérer directement le tampon Bytes, ce qui rend les choses beaucoup plus compliquées.
onetwopunch
8

Juste utiliser

foo := bufio.NewWriter(&b)

Parce que la façon dont bytes.Buffer implémente io.Writer est

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

Ça ne l'est b *Bufferpas b Buffer. (Je pense aussi que c'est bizarre car nous pouvons appeler une méthode par une variable ou son pointeur, mais nous ne pouvons pas affecter un pointeur à une variable de type non pointeur.)

De plus, l'invite du compilateur n'est pas assez claire:

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


Quelques idées, allez utiliser Passed by value, si nous passons bà buffio.NewWriter(), dans NewWriter (), c'est un nouveau b(un nouveau tampon), pas le tampon d'origine que nous avons défini, donc nous devons passer l'adresse&b .

Ajoutez à nouveau, octets.Buffer est défini:

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

en utilisant passed by value, la nouvelle structure de tampon passée est différente de la variable de tampon d'origine.

wmlhust
la source