为什么Go的io包中没有RuneWriter接口?

4

Go的io 包含以下接口(其中之一):

type ByteReader interface {
        ReadByte() (c byte, err error)
}

type ByteScanner interface {
        ByteReader
        UnreadByte() error
}

type ByteWriter interface {
        WriteByte(c byte) error
}

type RuneReader interface {
        ReadRune() (r rune, size int, err error)
}

type RuneScanner interface {
        RuneReader
        UnreadRune() error
}

但是没有 RuneWriter 接口:

type RuneWriter interface {
        WriteRune(r rune) (size int, err error)
}

Is there a reason that RuneWriter is missing?


如果你需要这样的东西,那么就在你自己的代码/包中定义它。在许多地方,标准包只定义了它们使用/需要的内容,而不是完整的集合。据我所知,bufio.Reader 是标准包中唯一可以实现你的 RuneWriter 的东西(而且 bufio.Reader 还有许多其他方法也不是任何接口的一部分)。 - Dave C
@DaveC:但是他们不应该定义他们期望用户需要什么,而不仅仅是他们自己需要的吗? - Matt
1
不要去猜测任何用户可能需要什么。接口的定义非常简单,只需按需定义即可。将RuneWriter添加到io包中也没有任何帮助。 - Dave C
就像我之前所说的,如果你在代码中有一个地方想要调用类似于WriteRune的东西,你可以选择a)创建自己的接口并将其作为参数接受,或者b)接受一个io.Reader参数,如果类型断言到你自己的接口失败,则将其包装在bufio.Reader中。由于bufio.Reader是标准包中唯一实现它的东西,因此(a)实际上只能强制调用者在bufio.Reader中进行包装(或者他们自己版本的类似物)。 - Dave C
请查看类似compress/flate.NewReader的内容,它可以做到这一点 - Dave C
@DaveC:另外,你关于 bufio.Reader 是唯一实现它的说法是错误的。bytes.Buffer 也实现了它。而且这些都是唯一实现 io.ByteWriter 的东西。那么为什么它们有 io.ByteWriter 而没有 io.RuneWriter 呢? - Matt
2个回答

4
Go语言开发者根据需要定义接口,而不是为了填充可能方法的网格而定义接口。这个策略有助于保持标准库的简洁性和小巧性。
我认为他们得出结论是:因为在标准包或其它他们维护的包中没有需要RuneWriter接口的情况。
Go团队之外并没有对该接口的需求。在问题跟踪器、邮件列表或可用的irc频道记录历史上都没有接口请求。
其他问题中提到的接口是应用于Go作者所维护的标准包或其它包中的。
你可以在自己的包或代码中定义接口。这是一个非常有用的特性,也是Go语言相对独特的地方。

1
Go语言的作者们认为没有必要使用RuneWriter接口。那么我的问题是:为什么他们认为不需要呢?他们认为在标准包或任何子存储库包中都不需要它。但ByteWriter也是一样。 - Matt
是的,我可以定义自己的接口,但将其放在标准库中的美妙之处在于它使第三方库之间的兼容性比它们必须定义自己的接口时更高。 - Matt
3
为了保证接口的兼容性,并不需要使用相同的名称。例如,我可以定义一个名为Foobar的接口,包含Read([]byte) (int,error)方法,这个接口与io.Reader或其他等效接口完全兼容。也就是说,我可以编写接受或返回我的接口类型参数的函数,而其他人也可以将其传递给或赋值给io.Reader。重要的是方法签名,而不是接口本身。 - Dave C
1
ByteWriter 在标准库中被用于四到五个位置。 - user4122236
3
再次看一下标准库中定义自己的特定接口的地方的示例(例如我之前提到的压缩包示例)。将这些接口的集合“标准化”是毫无意义的。 - Dave C

2

对Be Bop的回答进行小小的补充:

接口有助于定义通用函数。例如,func f(foo interface { Foo() }) 表示“我是函数f,如果你给我一个可以使用Foo()的东西,我会做好工作。”

现在考虑像 RuneScanner 这样的接口。一个 RuneScanner 提供了非平凡的方法,特别是 UnreadRune,这个方法不能很容易地通过“更低级别”的东西来模拟。

RuneWriter 接口有什么好处呢?定义一个函数 func g(rw RuneWriter),它表示“给我一个可以写符文的东西,我就能完成我的工作!”?但是实际上没有必要,因为这可以通过标准手段轻松模拟:将其定义为 func g(r io.Writer),然后在内部使用 fmt.Fprintf(r ...) 即可。

如果要写符文,必须具备写入1到6(?)个字节的能力,而这正是 io.Writer 提供的。所以不需要 RuneWriter

引入 RuneWriter 会让代码更易读或更安全吗?可能不会:函数 func g(rw RuneWriter) 明确表示它只希望将符文写入其参数。这很好,但对于编写更好的程序并不是真正有用的。一个符文是1到6个字节,g 提供的唯一额外承诺是“写入我的参数的任何内容都将是有效的UTF-8编码流”。这是一个非常浅显的承诺。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接