英文:
Implementing Reader interface
问题
我理解Go语言接口的一般概念。然而,最近我在研究如何实现io.Reader
接口时感到困惑。我找到了这篇帖子,但并没有太大帮助。
https://stackoverflow.com/questions/25526790/reader-interface-and-the-read-method-in-golang
首先,被接受的答案使用了io.Reader
的Read
函数,但据我所知,它从未被实现过。其次,在像ioutil.ReadAll
这样的情况下,Read
函数是如何工作的呢?它接受实现了io.Reader
接口的对象,并返回一个字节切片。我不明白一个只返回int
和err
的函数如何被处理成一个字节切片。
编辑:
我在go-nuts IRC频道得到了帮助,这是他们提供的实际实现方式的答案:http://play.golang.org/p/ejpUVOx8jR。非常感谢Go社区的帮助。
编辑2:
正如下面指出的,上面的实现在字符串大于缓冲区时会失败。这是一个更合理的实现:http://play.golang.org/p/t4Zg8TnF33。
英文:
I understand the general concept of Go's interfaces. However, I was recently looking into implementing the io.Reader
interface, and it has me confused. I found this post which didn't help to much.
https://stackoverflow.com/questions/25526790/reader-interface-and-the-read-method-in-golang
To start with, the accepted answer is using io.Reader
's Read
function, which as far as I can tell is never implemented. Second, how does the Read
function work in the context of something like ioutil.ReadAll
. It takes something that implemented the io.Reader
interface and returns a slice of bytes. I don't understand how something that is returning only an int
and err
can be processed into a slice of bytes.
Edit:
I was helped in the go-nuts IRC channel and this was the provided answer as to how you would likely actually implement one http://play.golang.org/p/ejpUVOx8jR. Much thanks to the go community.
Edit 2:
as pointed out below the implementation above will fail in the case where the strign is larger than the buffer. This is a more sane implementation http://play.golang.org/p/t4Zg8TnF33.
答案1
得分: 16
你将字节切片传递给了Read
函数。Read
函数应该将字节放入该切片中。由于切片只是对数组的引用,改变切片的内容会改变底层数组,因此Read
函数的调用者可以直接检查传递给它的切片。
ioutil.ReadAll
函数创建一个缓冲区并调用其上的ReadFrom
方法。ReadFrom
方法会重复调用Read
方法,增加缓冲区的大小,直到Read
方法返回io.EOF
作为错误,表示已经读取完毕。你可以自己查看。
你提供的答案实现了io.Reader
接口。它声明了一个方法Read(p []byte) (n int, e error)
。这就是所需的全部内容。
英文:
You pass Read
the byte slice. Read
is supposed to put bytes in it. As slices are just references to arrays, changing the contents of a slice changes the underlying array, so the caller of Read
can then just check the slice it has passed to it.
ioutil.ReadAll
creates a buffer and calls ReadFrom
on it. ReadFrom
calls Read
repeatedly, increasing the size of the buffer until Read
tells it has been exhausted by returning io.EOF
as error. See for yourself.
The answer you link does implement the io.Reader
interface. It is declaring a method Read(p []byte) (n int, e error)
. That's all what is needed.
答案2
得分: 8
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)。
英文:
The updated answer provided by tez totally works, but here is an alternative that I think is a bit cleaner utilizing Go's 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
}
By using copy
, you don't have to worry about overflowing p []byte
. This also doesn't drain/destroy any state that you have on your reader, instead it just iterates over it with readIndex
.
Full example here: https://play.golang.org/p/8QTECCkies
This strategy can be seen in some of Go's core packages (ie. https://golang.org/src/strings/reader.go)
答案3
得分: 1
只是提醒一下,你在这里实现的Read()
方法(http://play.golang.org/p/ejpUVOx8jR)是不正确的。你没有考虑到提供的p []byte
参数的容量。如果它小于你的测试字符串,你将会得到一个"index out of range"的错误(例如:http://play.golang.org/p/DhcY0hJ0c0)。
你可以考虑使用不同的方法,比如这个 - http://play.golang.org/p/t4Zg8TnF33。
更新
我注意到我的实现中存在内存泄漏。修复后的版本在这里 - http://play.golang.org/p/9BbS54d8pb。这表明即使是一个简单的代码有时也不那么简单
英文:
Just to note, your implementation of Read()
method here (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).
You might consider a different approach such as this - http://play.golang.org/p/t4Zg8TnF33.
UPDATE
I noticed a memory leak in my implementation. The fixed version is here - http://play.golang.org/p/9BbS54d8pb. This goes to show that even a trivial code sometimes is not so trivial
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论