本文来自正在规划的Go语言&云原生自我提升系列,欢迎关注后续文章。
使用Go进行开发的最大优势之一是其标准库。与Python类似,Go也采取了“内置电池”的理念,提供了构建应用程序所需的许多工具。由于Go是一种相对较新的语言,它附带了一个专注于现代编程环境中遇到的问题的库。
我们无法涵盖所有标准库包,所幸也不需要,因为有许多优秀的信息源可以了解标准库,比如官方文档。我们将重点关注几个最重要的包及其设计和用法来演示地道Go语言的基本原则。一些包(errors
、sync
、context
、testing
、reflect
和unsafe
)在各自的章节中进行过介绍。在本章中,我们将学习Go对I/O、时间、JSON和HTTP的内置支持。
I/O和它的小伙伴们
要使程序有价值,它需要能读取和写出数据。Go的输入/输出理念的核心在io
包中有体现。特别是,在该包中定义的两个接口可能是Go中第二和第三最常用的接口:io.Reader
和io.Writer
。
注:第一名是谁呢?自然是error
,我们已经在错误处理一章中学习过了。
io.Reader
和io.Writer
各自定义了一个方法:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
io.Writer
接口中的Write
方法接收一个字节切片参数,位于接口的实现中。它返回写入的字节数,如果出现错误则返回错误信息。io.Reader
中的Read
方法更有趣。它不是通过返回参数来返回数据,而是将一个切片作为入参传入实现,并进行修改。最多会将len(p)
个字节写入到该切片中。该方法返回写入的字节数。这可能看起来有点奇怪。读者期望的可能是:
type NotHowReaderIsDefined interface {
Read() (p []byte, err error)
}
标准库中定义io.Reader
的方式是有原因的。我们来编写一个函数说明如何使用io.Reader
方便大家理解:
func countLetters(r io.Reader) (map[string]int, error) {
buf := make([]byte, 2048)
out := map[string]int{}
for {
n, err := r.Read(buf)
for _, b := range buf[:n] {
if (b >= 'A' && b = 'a' && b