Go1.17 快報(bào)之標(biāo)準(zhǔn)庫(kù)越來(lái)越注重易用性
閱讀本文大概需要 5 分鐘。
大家好,我是 polarisxu。
說(shuō)起 Go 的優(yōu)點(diǎn),很多人會(huì)提到 Go 擁有強(qiáng)大的標(biāo)準(zhǔn)庫(kù),比如開發(fā)一個(gè) HTTP 服務(wù),幾行代碼就搞定。不過(guò),如果是一個(gè) PHPer 轉(zhuǎn)到 Go,又會(huì)覺(jué)得 Go 標(biāo)準(zhǔn)庫(kù)不夠便利,很多東西都需要自己二次封裝。這其實(shí)是一個(gè)取舍的問(wèn)題。
Go 官方也在不斷完善、優(yōu)化標(biāo)準(zhǔn)庫(kù),在堅(jiān)持一定原則的基礎(chǔ)上,盡可能讓標(biāo)準(zhǔn)庫(kù)好用、易用。今天就看看 Go1.17 中,官方在這方面做了哪些改進(jìn)。
01 time 包
Unix 時(shí)間戳,大家知道單位是什么嗎?Java 或 JavaScript 的同學(xué)大概率會(huì)回答是毫秒,因?yàn)檫@兩門語(yǔ)言提供獲取“時(shí)間戳”的方法,單位是毫秒。但實(shí)際上,標(biāo)準(zhǔn)的 Unix 時(shí)間戳,單位是秒,標(biāo)準(zhǔn)定義是:
Unix 時(shí)間戳是從 1970 年 1 月 1 日(UTC/GMT 的午夜)開始所經(jīng)過(guò)的秒數(shù),不考慮閏秒。
正因?yàn)槿绱?,Go 標(biāo)準(zhǔn)庫(kù) time 包提供獲取時(shí)間戳的方法是 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
在和客戶端/前端協(xié)商 API 時(shí),一定要注意時(shí)間戳單位的問(wèn)題。
為了方便,Go1.17 增加加了 Time.UnixMilli 方法,返回 Unix 時(shí)間戳的毫秒數(shù),同時(shí)也提供了 UnixNano 和 UnixMicro。
此外,如果前端傳遞一個(gè)毫秒的時(shí)間戳,可以通過(guò) Go1.17 新的函數(shù) UnixMilli 轉(zhuǎn)為 Time 類型:
func UnixMilli(msec int64) Time
注意 UnixMilli 函數(shù)和 Time.UnixMilli 方法的區(qū)別,互逆的關(guān)系。
02 net/url 包
在這個(gè)包中有一個(gè)類型 Values,定義如下:
type Values map[string][]string
它通常用于查詢參數(shù)和表單值。它提供了 Set、Get、Del 等方法,但沒(méi)有提供判斷某個(gè) key 是否設(shè)置了的方法(雖然自己實(shí)現(xiàn)不難,但形式不一致),而且這種需求還挺多的。Go1.17 就增加了一個(gè)方法:Has,用來(lái)判斷某個(gè) key 是否設(shè)置了。
// Has checks whether a given key is set.
func (v Values) Has(key string) bool
03 net 包
如何判斷一個(gè) IP 地址是否是內(nèi)網(wǎng)地址?你查找標(biāo)準(zhǔn)庫(kù)會(huì)發(fā)現(xiàn)沒(méi)有這樣的方法,這時(shí)只能自己實(shí)現(xiàn),需要查找 IPv4 標(biāo)準(zhǔn),看哪些是內(nèi)網(wǎng)地址,還得處理 IPv6 的情況。
Go1.17 中增加了一個(gè)方法:IsPrivate,用來(lái)判斷一個(gè) IP 地址是否是內(nèi)網(wǎng)地址:
// IsPrivate reports whether ip is a private address, according to
// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
func (ip IP) IsPrivate() bool
是不是方便很多。看它的實(shí)現(xiàn),自己實(shí)現(xiàn)可能不那么容易:
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 三個(gè)常量,分別對(duì)應(yīng) int 的最大、最小值和 uint 的最大值,這樣我們不需要自己判斷當(dāng)前 CPU 架構(gòu)確定最大最小值。
io/fs 包新增加 FileInfoToDirEntry 函數(shù),它用于獲取一個(gè) FileInfo 的 DirEntry 信息,在操作文件系統(tǒng)時(shí)可能會(huì)用到。
func FileInfoToDirEntry(info FileInfo) DirEntry
database/sql 包新增加了 NullByte 和 NullInt16,用于表示可能為 null 的 int16 和 byte 類型(我個(gè)人不建議創(chuàng)建數(shù)據(jù)表時(shí)支持 null,這樣處理起來(lái)比較麻煩,建議全部 NOT NULL)。
05 總結(jié)
簡(jiǎn)單、易用,一直是 Go 的哲學(xué)。標(biāo)準(zhǔn)庫(kù)方面,Go 也會(huì)盡可能的做到易用,但不會(huì)封裝到像 PHP 那樣的程度,有些功能,還是需要自己進(jìn)行二次封裝。
你覺(jué)得 Go1.17 上面的改進(jìn)如何?還有哪些功能是你希望標(biāo)準(zhǔn)庫(kù)提供的?歡迎留言交流。
我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語(yǔ)言并創(chuàng)建了 Go 語(yǔ)言中文網(wǎng)!著有《Go語(yǔ)言編程之旅》、開源圖書《Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)》等。
堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio
