Skip to content

Latest commit

 

History

History

chapter8

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

Chapter8

记录日志

程序输出 stdout,程序日志 stderr。

如果用户的程序只记录日志,没有程序输出,更常用的方式是将一般的日志信息写到 stdout,将错误或者警告信息写到 stderr。

log

log 包的实现,是基于对记录日志这个需求长时间的实践和积累而形成的。 将输出写到stdout,将日志记录到 stderr,是很多基于命令行界面(CLI)的程序的惯常使用的方法。 不过如果你的程序只输出日志,那么使用 stdout、stderr 和文件来记录日志是很好的做法。

itoa

关键字 iota 在常量声明区里有特殊的作用。 这个关键字让编译器为每个常量复制相同的表达式,直到声明区结束,或者遇到一个新的赋值语句。 关键字 iota 的另一个功能是,iota 的初始值为 0,之后 iota 的值在每次处理为常量后,都会自增 1。

// 操作符<<对左边的操作数执行按位左移操作。
// 在每个常量声明时,都将 1 按位左移 iota 个位置。
const (
    Ldate=1<<iota   //1<<0=000000001=1
    Ltime           //1<<1=000000010=2
    Lmicroseconds   //1<<2=000000100=4
    Llongfile       //1<<3=000001000=8
    Lshortfile      //1<<4=000010000=16
)

log.New()

log 包的源代码里的 New 函数的声明:

  • 第一个参数 out 指定了日志要写到的目的地。这个参数传入的值必须实现了 io.Writer 接口。
  • 第二个参数 prefix 是 之前看到的前缀,
  • 第三个参数是日志的标志

encode/decode (编码/解码)

json

struct 可以使用标签(tag),提供每个字段的元信息,将 JSON 文档和结构类型里的字段一一映射起来。 如果不存在标签,编码和解码过程会试图以大小写无关的方式,直接使用字段的名字进行匹配。 如果无法匹配,对应的结构类型里的字段就包含其零值。

Decode 方法可以接受任意类型的值。使用反射,Decode 方法会拿到传入值的类型信息。 然后,在读取 JSON 响应的过程中,Decode 方法会将对应的响应解码为这个类型的值。 这意味着用户不需要创建对应的值,Decode 会为用户做这件事情。

  • Unmarshal 将 json 文档转换为 Go 语言的 map 类型的值或者结构类型
  • Marshal 将 Go 语言的 map 类型的值或者结构类型的值转换为 json 文档
  • MarshalIndent 将 Go 语言的 map 类型的值或者结构类型的值转换为易读的 json 文档
  • Marshal 和 MarshalIndent 会使用反射来确定如何将 map 类型转换为 JSON 字符串

jsoniter

go 自带的 encode/json 包在处理 json 时性能不足。

开源的 jsoniter 是公认的性能较好的 json 编解码工具。

io (输入和输出)

所有实现了 io.Writer 和 io.Reader 两个接口类型的值,都可以使用 io 包提供的所有功能, 也可以用于其他包里接受这两个接口的函数以及方法。

io.Writer

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

io.Reader

type Reader interface {
    Read(p []byte) (n int, err error)
}
// (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 值的错误。调用者需要将这种返回状态视为没有做任何操作,而不是遇到读取结束。