实现 Reader 接口

huangapple go评论90阅读模式
英文:

Implementing Reader interface

问题

我理解Go语言接口的一般概念。然而,最近我在研究如何实现io.Reader接口时感到困惑。我找到了这篇帖子,但并没有太大帮助。

https://stackoverflow.com/questions/25526790/reader-interface-and-the-read-method-in-golang

首先,被接受的答案使用了io.ReaderRead函数,但据我所知,它从未被实现过。其次,在像ioutil.ReadAll这样的情况下,Read函数是如何工作的呢?它接受实现了io.Reader接口的对象,并返回一个字节切片。我不明白一个只返回interr的函数如何被处理成一个字节切片。

编辑:

我在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。这表明即使是一个简单的代码有时也不那么简单 实现 Reader 接口

英文:

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 实现 Reader 接口

huangapple
  • 本文由 发表于 2015年1月28日 00:14:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/28174970.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定