嵌入式接口

huangapple go评论122阅读模式
英文:

Embedded Interface

问题

我对Go还不太熟悉,我很惊讶地发现无法使用嵌入接口的子类型。下面是一个小例子来解释我的意思:

  1. func test(sl bufio.ReadWriter){
  2. // 无法将sl(类型为bufio.ReadWriter)作为函数参数中的bufio.Reader使用
  3. readStuff(sl)
  4. [...]
  5. writeStuff(sl) // 同样的错误类型
  6. }
  7. func readStuff(sl bufio.Reader){
  8. [...]
  9. }

由于每个接口具有相同的内存布局,并且ReadWriter是Reader和Writer,我期望这段代码能够工作。我尝试使用以下方式将接口类型转换为Reader:

  1. readStuff(sl.(buffio.Reader))

但这也不起作用。所以我有两个问题:

  • 为什么它不起作用?
  • Go对这个问题的哲学是什么?
英文:

I'm still quite new to Go and I was surprised to not be able to use the subtype of an embedded interface.
Here is a small example to explain what I mean:

  1. func test(sl bufio.ReadWriter){
  2. // cannot use sl(type bufio.ReadWriter) as type bufio.Reader in function argument
  3. readStuff(sl)
  4. [...]
  5. writeStuff(sl) // same kind of error
  6. }
  7. func readStuff(sl bufio.Reader){
  8. [...]
  9. }

As every interface have the same memory layout and ReadWriter is a Reader and a Writer, I was expecting this code to work.
I did try to convert the interface type with:

  1. readStuff(sl.(buffio.Reader))

But it doesn't work either. So I've got two questions:

  • Why doesn't it work?
  • What's the go philosophy about that problem?

答案1

得分: 7

它们是不同的类型。然而,bufio.ReadWriter 包含一个指向 bufio.Reader 类型和 bufio.Writer 类型的指针作为其结构的元素。因此,传递正确的一个应该很容易。尝试这样做:

  1. func test(sl bufio.ReadWriter){
  2. readStuff(sl.Reader)
  3. [...]
  4. writeStuff(sl.Writer)
  5. }
  6. // 将这个 bufio.Reader 改为指针接收器
  7. func readStuff(sl *bufio.Reader) {
  8. [...]
  9. }
英文:

They're different types. However, a bufio.ReadWriter contains a pointer to both a bufio.Reader type and a bufio.Writer type as elements of its struct. So passing the correct one should be easy enough. Try this:

  1. func test(sl bufio.ReadWriter){
  2. readStuff(sl.Reader)
  3. [...]
  4. writeStuff(sl.Writer)
  5. }
  6. // Changed this bufio.Reader to a pointer receiver
  7. func readStuff(sl *bufio.Reader) {
  8. [...]
  9. }

答案2

得分: 6

bufio.ReadWriter 是一个具体类型,而不是一个接口。然而,它确实满足一个接口 (io.ReadWriter),因此可以将其赋值给一个合适接口类型的变量/函数参数。然后它按照你可能预期的方式工作(你的代码实际上没有使用任何接口):

  1. package main
  2. import (
  3. "bufio"
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "log"
  8. )
  9. func readStuff(r io.Reader) {
  10. b := make([]byte, 10)
  11. n, err := r.Read(b)
  12. if err != nil && err != io.EOF {
  13. log.Fatal(err)
  14. }
  15. fmt.Printf("readStuff: %q\n", b[:n])
  16. }
  17. func writeStuff(w io.Writer) {
  18. b := []byte("written")
  19. n, err := w.Write(b)
  20. if n != len(b) {
  21. log.Fatal("Short write")
  22. }
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26. }
  27. func test(rw io.ReadWriter) {
  28. readStuff(rw)
  29. writeStuff(rw)
  30. }
  31. func main() {
  32. r := io.Reader(bytes.NewBufferString("source"))
  33. var uw bytes.Buffer
  34. w := io.Writer(&uw)
  35. rw := bufio.NewReadWriter(bufio.NewReader(r), bufio.NewWriter(w))
  36. test(rw)
  37. rw.Flush()
  38. fmt.Printf("The underlying bytes.Buffer writer contains %q\n", uw.Bytes())
  39. }

(也可以在这里查看)


输出:

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

这样 test 可以消费任何 io.ReadWriter,而不仅仅是特定的一个。这是关于你关于 Go "哲学" 的问题的一个提示。

英文:

bufio.ReadWriter is a concrete type, not an interface. However, it does satisfy an interface (io.ReadWriter) so it can be assigned to a variable/function argument of an appropriate interface type. Then it works the way you may have anticipated (your code actually doesn't use any interfaces):

  1. package main
  2. import (
  3. "bufio"
  4. "bytes"
  5. "fmt"
  6. "io"
  7. "log"
  8. )
  9. func readStuff(r io.Reader) {
  10. b := make([]byte, 10)
  11. n, err := r.Read(b)
  12. if err != nil && err != io.EOF {
  13. log.Fatal(err)
  14. }
  15. fmt.Printf("readStuff: %q\n", b[:n])
  16. }
  17. func writeStuff(w io.Writer) {
  18. b := []byte("written")
  19. n, err := w.Write(b)
  20. if n != len(b) {
  21. log.Fatal("Short write")
  22. }
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26. }
  27. func test(rw io.ReadWriter) {
  28. readStuff(rw)
  29. writeStuff(rw)
  30. }
  31. func main() {
  32. r := io.Reader(bytes.NewBufferString("source"))
  33. var uw bytes.Buffer
  34. w := io.Writer(&uw)
  35. rw := bufio.NewReadWriter(bufio.NewReader(r), bufio.NewWriter(w))
  36. test(rw)
  37. rw.Flush()
  38. fmt.Printf("The underlying bytes.Buffer writer contains %q\n", uw.Bytes())
  39. }

(Also here)


Output:

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

This way test can consume any io.ReadWriter, not only a specific one. Which is a hint towards your question about go "philosophy".

huangapple
  • 本文由 发表于 2012年12月17日 04:56:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/13905398.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定