程序输出 stdout,程序日志 stderr。
如果用户的程序只记录日志,没有程序输出,更常用的方式是将一般的日志信息写到 stdout,将错误或者警告信息写到 stderr。
log 包的实现,是基于对记录日志这个需求长时间的实践和积累而形成的。 将输出写到stdout,将日志记录到 stderr,是很多基于命令行界面(CLI)的程序的惯常使用的方法。 不过如果你的程序只输出日志,那么使用 stdout、stderr 和文件来记录日志是很好的做法。
关键字 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 函数的声明:
- 第一个参数 out 指定了日志要写到的目的地。这个参数传入的值必须实现了 io.Writer 接口。
- 第二个参数 prefix 是 之前看到的前缀,
- 第三个参数是日志的标志
struct 可以使用标签(tag),提供每个字段的元信息,将 JSON 文档和结构类型里的字段一一映射起来。 如果不存在标签,编码和解码过程会试图以大小写无关的方式,直接使用字段的名字进行匹配。 如果无法匹配,对应的结构类型里的字段就包含其零值。
Decode 方法可以接受任意类型的值。使用反射,Decode 方法会拿到传入值的类型信息。 然后,在读取 JSON 响应的过程中,Decode 方法会将对应的响应解码为这个类型的值。 这意味着用户不需要创建对应的值,Decode 会为用户做这件事情。
- Unmarshal 将 json 文档转换为 Go 语言的 map 类型的值或者结构类型
- Marshal 将 Go 语言的 map 类型的值或者结构类型的值转换为 json 文档
- MarshalIndent 将 Go 语言的 map 类型的值或者结构类型的值转换为易读的 json 文档
- Marshal 和 MarshalIndent 会使用反射来确定如何将 map 类型转换为 JSON 字符串
go 自带的 encode/json
包在处理 json 时性能不足。
开源的 jsoniter
是公认的性能较好的 json 编解码工具。
所有实现了 io.Writer 和 io.Reader 两个接口类型的值,都可以使用 io 包提供的所有功能, 也可以用于其他包里接受这两个接口的函数以及方法。
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绝不能改写切片里的数据,哪怕是临时修改也不行。
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 值的错误。调用者需要将这种返回状态视为没有做任何操作,而不是遇到读取结束。