5.io.ReaderFrom接口
*这是在生病前更新的最后一篇,时隔近2月有余,已经忘得差不多了,现在重新从这一节开始整理边看边补吧。
2017-9-23
ReaderFrom接口在bufio包的bufio.go中有实现,bufio是什么意思?一看名字可以猜得出,是带了buffer缓存的io包。
通俗地来讲,就是io的威力加强版。
可见,io就是一个简单的小骨架,他是开枝散叶的,散布于各方法之中,由其调用。
先看一段实现的方法:
1 | func main() { |
输出:
1 | Hello world! |
这里我们先不用深究bufio是怎么用的,strings.NewReader是将“hello world”这个字符串转换成Reader的结构体。
1 | type Reader struct { |
bufio.NewWriter就确定buffer的尺寸。
最后用ReadFrom将s读入到bw中。
1 | // 同样,实现了io.ReaderFrom |
在ReadFrom中有一个判断:if b.Buffered() == 0 {}
翻到buffered()方法的代码中
1 | // Buffered returns the number of bytes that have been written into the current buffer. |
会发现有一个b.n
这其实是一个Writer结构里的一个字段。
1 | type Writer struct { |
(注意:Writer implements buffering for an io.Writer object.)
这个Writer也是实现了io.Writer的。
不过我没找到n的用法,在我上面的例子中。
1 | if b.Buffered() == 0 { |
b.wr是什么,b.wr就是b := bytes.NewBuffer(make([]byte, 10))
在这一段是必然会return了,因为b.Buffered()为0。到b.wr.(io.ReaderFrom)的时候,即强行把b.wr转换成了io.ReaderFrom(这个的意思是现在w只拥有ReadFrom这一个方法)并赋值给了w。
也就是说,这里的return w.ReadFrom(r),就是b.ReadFrom(r),是否如此,还需验证一下。
1 | func main() { |
输出:
1 | 14 |
奇怪,怎么val1是14,val2是0了,实际上原因就在于ReadFrom()只会读一次就把buff给清了。
1 | // If buffer is empty, reset to recover space. |
b.off在第一次调用的时候会置为0。
如果我们把第一次的ReadFrom()去掉,即删除val1,err := b.ReadFrom(s),再打印的时候val2就是14了。
接下来,再做个简单的回顾:
首先:bytes.NewBuffer,返回了一个{ return &Buffer{buf: buf} }Buffer的对象。赋值给b。
1 | type Buffer struct { |
此位于bytes包的buffer.go文件。
接下来:strings.NewReader,{ return &Reader{s, 0, -1} },返回了一个Reader对象。赋值给s。
1 | type Reader struct { |
此位于strings包的reader.go文件。
再接下来:bufio.NewWriter(b),把b带入,最后返回的是一个Writer对象。赋值给bw
1 | return &Writer{ |
这里就是关键,这个Writer对象里初始化了两个值,buf和wr,不过这两个值都是私有的,其中buf是大小,调用了系统的固定值,一个常量defaultBufSize,为4096。size = defaultBufSize
而w就是传入的b,也即Buffer的对象。传入的过程中已经被转换成了io.Writer对象。
现在的问题就是,这个转换过程,到底做了什么?
事实上我写了一段例子发现,传过去并没有做任何转换。
1 | func main() { |
这突然让我想起一件事情,io.Writer是个接口,而所有的变量的根都是继承自一个空的接口(interface{})
所以根本就没做什么转换,直接转过去就行了。
所以wr就是b本身。
最后:bw.ReadFrom(s)
在目录的例子子,这段程序只执行到:
1 | if b.Buffered() == 0 { |
就结束了,关键是w.ReadFrom(r)这一段,目前已经知道w就是b。实际上就也就是让b操作了一下ReadFrom(r)。
要注意的是这个ReadFrom(r)是buffer包里的ReadFrom(),位于src\bytes\buffer.go文件里面。
而bw.ReadFrom(s)调用的是bufio包里的ReadFrom(),位于src\bufio\bufio.go文件里面,是不一样的!
在bw.ReadFrom(s)里面,就把”Hello world!”这串string给了b。
所以就可以打印出来了
bufio的应用场景目前还不太清楚,这一段主要就是大概了解一下ReadFrom的使用情况。










