实现Reader接口

时间:2015-01-27 16:14:33

标签: go

我理解Go接口的一般概念。但是,我最近正在考虑实现io.Reader接口,这让我很困惑。我发现这篇文章并没有多大帮助。

Reader interface and the Read method in golang

首先,接受的答案是使用io.Reader的{​​{1}}函数,据我所知,该函数从未实现过。其次,Read函数如何在Read之类的上下文中工作。它需要实现ioutil.ReadAll接口并返回一个字节片。我不明白只返回io.Readerint的内容可以处理成一片字节。

编辑:

我在疯狂的IRC频道中得到了帮助,这就是你如何实际实现一个http://play.golang.org/p/ejpUVOx8jR的答案。非常感谢go社区。

编辑2:

如下所述,在strign大于缓冲区的情况下,上述实现将失败。这是一个更健全的实现http://play.golang.org/p/t4Zg8TnF33

3 个答案:

答案 0 :(得分:9)

您传递Read字节切片。 Read应该在其中放入字节。由于切片只是对数组的引用,因此更改切片的内容会更改基础数组,因此Read的调用者只需检查它传递给它的切片。

ioutil.ReadAll创建一个缓冲区并在其上调用ReadFromReadFrom重复调用Read,增加缓冲区的大小,直到Read通过返回io.EOF作为错误告诉它已经用尽。 See for yourself

您链接的答案确实实现了io.Reader界面。它声明了一种方法Read(p []byte) (n int, e error)。这就是所需要的一切。

答案 1 :(得分:3)

tez提供的更新答案完全有效,但是我认为使用Go copy是一个更清洁的替代方案:

type Reader struct {
    data []byte
    readIndex int64
}

func (r *Reader) Read(p []byte) (n int, err error) {
    if r.readIndex >= int64(len(r.data)) {
        err = io.EOF
        return
    }

    n = copy(p, r.data[r.readIndex:])
    r.readIndex += int64(n)
    return
}

使用copy,您不必担心溢出p []byte。这也不会消耗/破坏您在阅读器上的任何状态,而只是用readIndex迭代它。

此处的完整示例:https://play.golang.org/p/8QTECCkies

这个策略可以在Go的一些核心软件包中看到(即https://golang.org/src/strings/reader.go

答案 2 :(得分:1)

请注意,您在此处Read()方法的实施(http://play.golang.org/p/ejpUVOx8jR)不正确。您没有考虑提供的p []byte参数的容量。您将获得超出范围的"索引"如果它小于你的测试字符串会引起恐慌(例如:http://play.golang.org/p/DhcY0hJ0c0)。

您可以考虑使用其他方法 - http://play.golang.org/p/t4Zg8TnF33

<强>更新 我注意到我的实现中存在内存泄漏。固定版本在此处 - http://play.golang.org/p/9BbS54d8pb。这表明即使是一个微不足道的代码有时也不是那么简单:)