Go1.17 快报之标准库越来越注重易用性
大家好,我是 polarisxu。
说起 Go 的优点,很多人会提到 Go 拥有强大的标准库,比如开发一个 HTTP 服务,几行代码就搞定。不过,如果是一个 PHPer 转到 Go,又会觉得 Go 标准库不够便利,很多东西都需要自己二次封装。这其实是一个取舍的问题。
Go 官方也在不断完善、优化标准库,在坚持一定原则的基础上,尽可能让标准库好用、易用。今天就看看 Go1.17 中,官方在这方面做了哪些改进。
01 time 包
Unix 时间戳,大家知道单位是什么吗?Java 或 JavaScript 的同学大概率会回答是毫秒,因为这两门语言提供获取“时间戳”的方法,单位是毫秒。但实际上,标准的 Unix 时间戳,单位是秒,标准定义是:
Unix 时间戳是从 1970 年 1 月 1 日(UTC/GMT 的午夜)开始所经过的秒数,不考虑闰秒。
正因为如此,Go 标准库 time 包提供获取时间戳的方法是 Unix()
,单位是秒:
// Unix returns t as a Unix time, the number of seconds elapsed
// since January 1, 1970 UTC. The result does not depend on the
// location associated with t.
// Unix-like operating systems often record time as a 32-bit
// count of seconds, but since the method here returns a 64-bit
// value it is valid for billions of years into the past or future.
func (t Time) Unix() int64
在和客户端/前端协商 API 时,一定要注意时间戳单位的问题。
为了方便,Go1.17 增加加了 Time.UnixMilli 方法,返回 Unix 时间戳的毫秒数,同时也提供了 UnixNano 和 UnixMicro。
此外,如果前端传递一个毫秒的时间戳,可以通过 Go1.17 新的函数 UnixMilli 转为 Time 类型:
func UnixMilli(msec int64) Time
注意 UnixMilli 函数和 Time.UnixMilli 方法的区别,互逆的关系。
02 net/url 包
在这个包中有一个类型 Values,定义如下:
type Values map[string][]string
它通常用于查询参数和表单值。它提供了 Set、Get、Del 等方法,但没有提供判断某个 key 是否设置了的方法(虽然自己实现不难,但形式不一致),而且这种需求还挺多的。Go1.17 就增加了一个方法:Has,用来判断某个 key 是否设置了。
// Has checks whether a given key is set.
func (v Values) Has(key string) bool
03 net 包
如何判断一个 IP 地址是否是内网地址?你查找标准库会发现没有这样的方法,这时只能自己实现,需要查找 IPv4 标准,看哪些是内网地址,还得处理 IPv6 的情况。
Go1.17 中增加了一个方法:IsPrivate,用来判断一个 IP 地址是否是内网地址:
// IsPrivate reports whether ip is a private address, according to
// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
func (ip IP) IsPrivate() bool
是不是方便很多。看它的实现,自己实现可能不那么容易:
func (ip IP) IsPrivate() bool {
if ip4 := ip.To4(); ip4 != nil {
// Following RFC 1918, Section 3. Private Address Space which says:
// The Internet Assigned Numbers Authority (IANA) has reserved the
// following three blocks of the IP address space for private internets:
// 10.0.0.0 - 10.255.255.255 (10/8 prefix)
// 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
// 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
return ip4[0] == 10 ||
(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
(ip4[0] == 192 && ip4[1] == 168)
}
// Following RFC 4193, Section 8. IANA Considerations which says:
// The IANA has assigned the FC00::/7 prefix to "Unique Local Unicast".
return len(ip) == IPv6len && ip[0]&0xfe == 0xfc
}
04 其他包
math 包新提供了 MaxInt、MinInt、MaxUint 三个常量,分别对应 int 的最大、最小值和 uint 的最大值,这样我们不需要自己判断当前 CPU 架构确定最大最小值。
io/fs 包新增加 FileInfoToDirEntry 函数,它用于获取一个 FileInfo 的 DirEntry 信息,在操作文件系统时可能会用到。
func FileInfoToDirEntry(info FileInfo) DirEntry
database/sql 包新增加了 NullByte 和 NullInt16,用于表示可能为 null 的 int16 和 byte 类型(我个人不建议创建数据表时支持 null,这样处理起来比较麻烦,建议全部 NOT NULL)。
05 总结
简单、易用,一直是 Go 的哲学。标准库方面,Go 也会尽可能的做到易用,但不会封装到像 PHP 那样的程度,有些功能,还是需要自己进行二次封装。
你觉得 Go1.17 上面的改进如何?还有哪些功能是你希望标准库提供的?欢迎留言交流。