2012-12-16 5 views
9

Je suis encore assez nouveau pour Go et j'ai été surpris de ne pas pouvoir utiliser le sous-type d'une interface intégrée. Voici un petit exemple pour expliquer ce que je veux dire:Embedded Interface

func test(sl bufio.ReadWriter){ 
    // cannot use sl(type bufio.ReadWriter) as type bufio.Reader in function argument 
    readStuff(sl) 
    [...] 
    writeStuff(sl) // same kind of error 
} 

func readStuff(sl bufio.Reader){ 
    [...] 
} 

Comme chaque interface ont la même mise en page de mémoire et ReadWriter est un lecteur et un écrivain, je me attendais à ce code fonctionne. J'ai essayé de convertir le type d'interface avec:

readStuff(sl.(buffio.Reader)) 

Mais cela ne fonctionne pas non plus. J'ai donc deux questions:

  • Pourquoi ça ne marche pas?
  • Quelle est la philosophie de départ concernant ce problème?

Répondre

7

Ils sont de différents types. Cependant, un bufio.ReadWriter contient un pointeur vers un type bufio.Reader et un type bufio.Writer comme éléments de sa structure. Donc, passer le bon devrait être assez facile. Essayez ceci:

func test(sl bufio.ReadWriter){ 
    readStuff(sl.Reader) 
    [...] 
    writeStuff(sl.Writer) 
} 

// Changed this bufio.Reader to a pointer receiver 
func readStuff(sl *bufio.Reader) { 
    [...] 
} 
+0

Merci! Cela fonctionne avec readStuff (* sl.Reader) – user1612346

+0

J'aurais une deuxième question: et si tous mes paramètres sont des tranches au lieu d'un seul paramètre. Y at-il un moyen élégant de convertir une tranche de ReadWriter à une tranche de Reader? – user1612346

+2

Je pense que la solution la plus élégante que vous trouverez est de créer une nouvelle tranche et de la peupler via une boucle for. – Daniel

6

bufio.ReadWriter est un type concret, pas une interface. Cependant, il satisfait une interface (io.ReadWriter) de sorte qu'il peut être affecté à un argument variable/fonction d'un type d'interface approprié. Ensuite, il fonctionne de la façon dont vous avez peut-être prévu (votre code utilise ne fait aucune interface):

package main 

import (
     "bufio" 
     "bytes" 
     "fmt" 
     "io" 
     "log" 
) 

func readStuff(r io.Reader) { 
     b := make([]byte, 10) 
     n, err := r.Read(b) 
     if err != nil && err != io.EOF { 
       log.Fatal(err) 
     } 
     fmt.Printf("readStuff: %q\n", b[:n]) 
} 

func writeStuff(w io.Writer) { 
     b := []byte("written") 
     n, err := w.Write(b) 
     if n != len(b) { 
       log.Fatal("Short write") 
     } 

     if err != nil { 
       log.Fatal(err) 
     } 
} 

func test(rw io.ReadWriter) { 
    readStuff(rw) 
    writeStuff(rw) 
} 

func main() { 
     r := io.Reader(bytes.NewBufferString("source")) 
     var uw bytes.Buffer 
     w := io.Writer(&uw) 
     rw := bufio.NewReadWriter(bufio.NewReader(r), bufio.NewWriter(w)) 
     test(rw) 
     rw.Flush() 
     fmt.Printf("The underlying bytes.Buffer writer contains %q\n", uw.Bytes()) 
} 

(également here)


Sortie:

readStuff: "source" 
The underlying bytes.Buffer writer contains "written" 

De cette façon test peut consommer n'importe quel io.ReadWriter, non seulement un spécifique. Ce qui est un indice vers votre question sur aller "philosophie".