实现 Reader 接口
Implementing Reader interface
我了解 Go 接口的一般概念。但是,我最近正在研究实现 io.Reader
接口,这让我感到困惑。我发现这个 post 并没有多大帮助。
Reader interface and the Read method in golang
首先,接受的答案是使用 io.Reader
的 Read
函数,据我所知,该函数从未实现过。其次,Read
函数如何在 ioutil.ReadAll
之类的上下文中工作。它需要实现 io.Reader
接口和 returns 字节片段的东西。我不明白如何将仅返回 int
和 err
的内容处理成字节片段。
编辑:
我在 go-nuts IRC 频道中得到了帮助,这是关于您可能如何实际实施一个 http://play.golang.org/p/ejpUVOx8jR 的答案。非常感谢 go 社区。
编辑 2:
正如下面所指出的,如果字符串大于缓冲区,上面的实现将失败。这是一个更理智的实现 http://play.golang.org/p/t4Zg8TnF33.
你传递 Read
字节片。 Read
应该将字节放入其中。由于切片只是对数组的引用,更改切片的内容会更改底层数组,因此 Read
的调用者随后可以检查它传递给它的切片。
ioutil.ReadAll
创建一个缓冲区并在其上调用 ReadFrom
。 ReadFrom
重复调用 Read
,增加缓冲区的大小,直到 Read
通过返回 io.EOF
作为错误告诉它已经耗尽。 See for yourself.
您 link 的回答确实实现了 io.Reader
接口。它正在声明一个方法 Read(p []byte) (n int, e error)
。这就是所有需要的。
请注意,您在此处实施了 Read()
方法 (http://play.golang.org/p/ejpUVOx8jR) is incorrect. You do not account for a capacity of the provided p []byte
argument. You'll get an "index out of range" panic if it is smaller than your test string (ex: http://play.golang.org/p/DhcY0hJ0c0)。
您可能会考虑像这样的不同方法 - http://play.golang.org/p/t4Zg8TnF33。
更新
我注意到我的实现中存在内存泄漏。固定版本在这里 - http://play.golang.org/p/9BbS54d8pb。这表明即使是微不足道的代码有时也不是那么微不足道:)
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
。这也不会 drain/destroy 您在 reader 上的任何状态,而只是用 readIndex
.
迭代它
完整示例在这里:https://play.golang.org/p/8QTECCkies
这个策略可以在Go的一些核心包中看到(即。https://golang.org/src/strings/reader.go)
我了解 Go 接口的一般概念。但是,我最近正在研究实现 io.Reader
接口,这让我感到困惑。我发现这个 post 并没有多大帮助。
Reader interface and the Read method in golang
首先,接受的答案是使用 io.Reader
的 Read
函数,据我所知,该函数从未实现过。其次,Read
函数如何在 ioutil.ReadAll
之类的上下文中工作。它需要实现 io.Reader
接口和 returns 字节片段的东西。我不明白如何将仅返回 int
和 err
的内容处理成字节片段。
编辑:
我在 go-nuts IRC 频道中得到了帮助,这是关于您可能如何实际实施一个 http://play.golang.org/p/ejpUVOx8jR 的答案。非常感谢 go 社区。
编辑 2:
正如下面所指出的,如果字符串大于缓冲区,上面的实现将失败。这是一个更理智的实现 http://play.golang.org/p/t4Zg8TnF33.
你传递 Read
字节片。 Read
应该将字节放入其中。由于切片只是对数组的引用,更改切片的内容会更改底层数组,因此 Read
的调用者随后可以检查它传递给它的切片。
ioutil.ReadAll
创建一个缓冲区并在其上调用 ReadFrom
。 ReadFrom
重复调用 Read
,增加缓冲区的大小,直到 Read
通过返回 io.EOF
作为错误告诉它已经耗尽。 See for yourself.
您 link 的回答确实实现了 io.Reader
接口。它正在声明一个方法 Read(p []byte) (n int, e error)
。这就是所有需要的。
请注意,您在此处实施了 Read()
方法 (http://play.golang.org/p/ejpUVOx8jR) is incorrect. You do not account for a capacity of the provided p []byte
argument. You'll get an "index out of range" panic if it is smaller than your test string (ex: http://play.golang.org/p/DhcY0hJ0c0)。
您可能会考虑像这样的不同方法 - http://play.golang.org/p/t4Zg8TnF33。
更新 我注意到我的实现中存在内存泄漏。固定版本在这里 - http://play.golang.org/p/9BbS54d8pb。这表明即使是微不足道的代码有时也不是那么微不足道:)
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
。这也不会 drain/destroy 您在 reader 上的任何状态,而只是用 readIndex
.
完整示例在这里:https://play.golang.org/p/8QTECCkies
这个策略可以在Go的一些核心包中看到(即。https://golang.org/src/strings/reader.go)