NewReader你理解了?|青训营笔记

272 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记

io.Reader和它的变体们

在学习第一课的时候,不知道大家对一个地方有没有感到有点疑惑,也就是在第一个项目和第三个项目中出现的好几次 “NewReader”。

为了搞清楚这部分这样设计的缘由,我查了点资料,总结如下:

“bufio.NewReader(os.Stdin)”:

在第一个猜数字的项目中,我们第一次看到bufio包,和它的NewReader()方法。NewReader()中传入了一个叫做os.Stdin的东西,在编译器上我们可以看到NewReader()方法要求传入的是一个 io.Reader类型的值,而其实os.Stdin是os包中的file指针类型,其实这就是Go中经典的面向接口编程的实现例子,io.Reader()实际上是一个接口,而我们os.Stdin实现了io.Reader()的接口方法,按照Go的规则,它就可以赋值给这个类型变量了。bufio是buffered I/O 的意思,主要目的是提高读取的效率,当然这里你可以用别的包来读,如strings.NewReader()。下面就有用到,

“ var data = bytes.NewReader(buf)”:

这是在第二个项目中的,buf, err := json.Marshal(request)在完成了json的序列化得到了 byte[]后,下面的http.NewRequest()的第3个参数用到的是类型是io.Reader,也就是要传入一个实现了io.Reader接口的变量,就像上面所说,我们这里就用了,因为我们得到的是字节切片,所以就用了var data = bytes.NewReader(buf)

为什么要这样设计?

  1. 用io包来定义简单接口,这样就能很大程度地提高不同程序实体之间的互操作性,以io包中的一个函数为例,在io包中有一个io.CopyN()函数,他会接受两个参数,用于代表数据目的地的io.Writer类型的参数dst,和用于代表数据源地址的io.Reader类型的参数src。在使用这个函数时,无论我们的参数的类型是什么,只要我们实现的这两个接口的方法,那我们就可以把它们当作这个类型做为参数传入,当然了和CopyN类型的这些函数还是会对它们做必要的检查,检查不通过还是不可以运行的。但不得不说这样设计还是很大地提高了实体间的互操作性。换句话说就是,像string.Reader,bytes.Reader的这些类型,正是因为实现了不少的接口,所以它们的值才能够被使用在更广阔的场景中。
  2. 关于 http.NewRequest(),第三个参数参入的内容为什么要设计为io.Reader类型,个人理解有两点:1.就像上面的结论,设置为io.Reader,可以让这个Request 的body的来源不那么单一,.而是只要实现了接口方法的都行。2.像这些实现了io.Reader的类型,(String.Reader,bytes.Reader),它们在内部都有封装了对这些数据读取的最佳实践,可以让我们更高效地读取内容,用它们声明的变量都会用一个值保存以经读取的字节的计数,这样就可以很大地提高读取的效率。