一直学一直嗨,一直嗨一直学

Go语言Writer和Reader接口简述

Go语言中io包是围绕着实现了io.Writer和io.Reader接口类型的值而构建的。由于io.Writer和io.Reader提供了足够的抽象,这些io包里的函数和方法并不知道数据的类型,也不知道这些数据在物理上是如何读和写的。让我们先来看一下io.Writer接口的声明,代码如下所示。

typeWriterinterface{Write(p[]byte)(nint,errerror)}

上述代码中展示了io.Writer接口的声明。这个接口声明了唯一一个方法Write,这个方法接受一个byte切片,并返回两个值。第一个值是写入的字节数,第二个值是error错误值。

Write从p里向底层的数据流写入len(p)字节的数据。这个方法返回从p里写出的字节数(0<=n<=len(p)),以及任何可能导致写入提前结束的错误。Write在返回n<len(p)的时候,必须返回某个非nil值的error。Write绝不能改写切片里的数据,哪怕是临时修改也不行。

上述的规则来自标准库。这些规则意味着Write方法的实现需要试图写入被传入的byte切片里的所有数据。但是,如果无法全部写入,那么该方法就一定会返回一个错误。

返回的写入字节数可能会小于byte切片的长度,但不会出现大于的情况。最后,不管什么情况,都不能修改byte切片里的数据。

io.Reader接口的声明如下所示。

typeReaderinterface{Read(p[]byte)(nint,errerror)}

上述代码中的io.Reader接口声明了一个方法Read,这个方法接受一个byte切片,并返回两个值。第一个值是读入的字节数,第二个值是error错误值。实现Read方法需要注意以下几点:

1)Read最多读入len(p)字节,保存到p。这个方法返回读入的字节数(0<=n<=len(p))和任何读取时发生的错误。即便Read返回的n<len(p),方法也可能使用所有p的空间存储临时数据。如果数据可以读取,但是字节长度不足len(p),习惯上Read会立刻返回可用的数据,而不等待更多的数据。

2)当成功读取n>0字节后,如果遇到错误或者文件读取完成,Read方法会返回读入的字节数。方法可能会在本次调用返回一个非nil的错误,或者在下一次调用时返回错误(同时n==0)。这种情况的的一个例子是,在输入的流结束时,Read会返回非零的读取字节数,可能会返回err==EOF,也可能会返回err==nil。无论如何,下一次调用Read应该返回0,EOF。

3)调用者在返回的n>0时,总应该先处理读入的数据,再处理错误err。这样才能正确操作读取一部分字节后发生的I/O错误。EOF也要这样处理。

4)Read的实现不鼓励返回0个读取字节的同时,返回nil值的错误。调用者需要将这种返回状态视为没有做任何操作,而不是遇到读取结束。

标准库里列出了实现Read方法的4条规则。

第一条规则表明,该实现需要试图读取数据来填满被传入的byte切片。允许出现读取的字节数小于byte切片的长度,并且如果在读取时已经读到数据但是数据不足以填满byte切片时,不应该等待新数据,而是要直接返回已读数据。

第二条规则提供了应该如何处理达到文件末尾(EOF)的情况的指导。当读到最后一个字节时,可以有两种选择。一种是Read返回最终读到的字节数,并且返回EOF作为错误值,另一种是返回最终读到的字节数,并返回nil作为错误值。在后一种情况下,下一次读取的时候,由于没有更多的数据可供读取,需要返回0作为读到的字节数,以及EOF作为错误值。

第三条规则是给调用Read的人的建议。任何时候Read返回了读取的字节数,都应该优先处理这些读取到的字节,再去检查EOF错误值或者其他错误值。

第四条规则是约束建议Read方法的实现永远不要返回0个读取字节的同时返回nil作为错误值。如果没有读到值,Read应该总是返回一个错误。

Tags: