2012-12-16 11 views
9

Nadal jestem całkiem nowym produktem Go i byłem zaskoczony, że nie mogę korzystać z podtypu wbudowanego interfejsu. Oto mały przykład, aby wyjaśnić, co mam na myśli:Wbudowany interfejs

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){ 
    [...] 
} 

Jak każdego interfejsu mają ten sam układ pamięci i ReadWriter jest Reader i Writer, spodziewałem się ten kod do pracy. Próbowałem przekonwertować typ interfejsu z:

readStuff(sl.(buffio.Reader)) 

Ale to nie działa. Mam więc dwa pytania:

  • Dlaczego to nie działa?
  • Jaka jest filozofia dotycząca tego problemu?

Odpowiedz

7

Są to różne typy. Jednak bufio.ReadWriter zawiera wskaźnik zarówno typu bufio.Reader, jak i typu bufio.Writer jako elementów jego struktury. Przejście poprawnego powinno być łatwe. Wypróbuj to:

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

Dzięki! Działa z readStuff (* sl.Reader). – user1612346

+0

Mam drugie pytanie: co, jeśli cały mój parametr to plaster zamiast pojedynczego parametru. Czy istnieje jakiś elegancki sposób na przekonwertowanie plasterka ReadWriter na plaster Reader? – user1612346

+2

Myślę, że najbardziej eleganckim rozwiązaniem jest utworzenie nowego plasterka i zapełnienie go za pomocą pętli for. – Daniel

6

bufio.ReadWriter to rodzaj betonu, a nie interfejs. Jednak spełnia on interfejs (io.ReadWriter), więc można go przypisać do argumentu zmiennej/funkcji odpowiedniego typu interfejsu. Wtedy to działa tak, można przewidzieć (kod faktycznie nie używa żadnych interfejsów):

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()) 
} 

(Również here)


wyjściowa:

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

ten sposób test może zużywać dowolny io.ReadWriter, a nie tylko określony. Co jest wskazówką do twojego pytania o "filozofię".