英文:
Embedded Interface
问题
我对Go还不太熟悉,我很惊讶地发现无法使用嵌入接口的子类型。下面是一个小例子来解释我的意思:
func test(sl bufio.ReadWriter){
// 无法将sl(类型为bufio.ReadWriter)作为函数参数中的bufio.Reader使用
readStuff(sl)
[...]
writeStuff(sl) // 同样的错误类型
}
func readStuff(sl bufio.Reader){
[...]
}
由于每个接口具有相同的内存布局,并且ReadWriter是Reader和Writer,我期望这段代码能够工作。我尝试使用以下方式将接口类型转换为Reader:
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:
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){
[...]
}
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:
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
类型的指针作为其结构的元素。因此,传递正确的一个应该很容易。尝试这样做:
func test(sl bufio.ReadWriter){
readStuff(sl.Reader)
[...]
writeStuff(sl.Writer)
}
// 将这个 bufio.Reader 改为指针接收器
func readStuff(sl *bufio.Reader) {
[...]
}
英文:
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:
func test(sl bufio.ReadWriter){
readStuff(sl.Reader)
[...]
writeStuff(sl.Writer)
}
// Changed this bufio.Reader to a pointer receiver
func readStuff(sl *bufio.Reader) {
[...]
}
答案2
得分: 6
bufio.ReadWriter 是一个具体类型,而不是一个接口。然而,它确实满足一个接口 (io.ReadWriter),因此可以将其赋值给一个合适接口类型的变量/函数参数。然后它按照你可能预期的方式工作(你的代码实际上没有使用任何接口):
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())
}
(也可以在这里查看)
输出:
readStuff: "source"
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):
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())
}
(Also here)
Output:
readStuff: "source"
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".
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论