寫這篇博客緣由,因?yàn)槲以诰W(wǎng)上搜了很多篇關(guān)于 Go 1.13 的文章,但是很多是直接翻譯官方博客介紹的敏晤,對我們Go開發(fā)經(jīng)驗(yàn)不是很長的人來說,因?yàn)闆]有對應(yīng)大量實(shí)戰(zhàn)經(jīng)驗(yàn)缅茉,看了比較蒙嘴脾,理解不了,就是感覺看不懂為什么需要加這些新特性,所以就自己搜集了很多相關(guān)文章译打,消化理解之后寫出了這篇博客耗拓。Go 1.0發(fā)布到 1.13版本,Go語言本身的語法改動非常少奏司。
一乔询、內(nèi)容
1)Tools 變動
2)標(biāo)準(zhǔn)庫 變動
3)語言 spec 方面變動
4)跨平臺支持
二、Tools
-
- 升級到 Go 1.13 后 GOPROXY 和 GOSUMDB 都會有默認(rèn)值韵洋,且默認(rèn)值在國內(nèi)是無法訪問的竿刁,所以為了一切正常,建議大家
go env -w GOPROXY=https://goproxy.cn,direct
搪缨,這個(gè)命令是 Go 1.13 新加的食拜,然后 GOSUMDB 就不用改了,因?yàn)?goproxy.cn 支持代理它的默認(rèn)值副编,所以直接就能用负甸。在 Go1.13 之前,GOPROXY=https://goproxy.cn 即可痹届,逗號列表是 Go1.13 才有的呻待。 - 如果你用了 GOPROXY 或 GOSUMDB,那么你就可能需要了解一下 GONOPROXY队腐、GONOSUDB 還有 GOPRIVATE蚕捉。前兩個(gè)是指定 Go 該怎么處理模塊的下載與校驗(yàn);后三個(gè)是指定 Go 在那些情況下不應(yīng)該根據(jù)前兩個(gè)處理柴淘。所以鱼冀,私有庫的問題可以解決。
- 關(guān)于 GOPROXY悠就,看看 goproxy.cn 的作者發(fā)布的文章:goproxy.cn - 為中國 Go 語言開發(fā)者量身打造的模塊代理。
- 升級到 Go 1.13 后 GOPROXY 和 GOSUMDB 都會有默認(rèn)值韵洋,且默認(rèn)值在國內(nèi)是無法訪問的竿刁,所以為了一切正常,建議大家
-
Command
- go env 支持 -w 參數(shù)為用戶單獨(dú)設(shè)置環(huán)境變量充易,-u 參數(shù)取消設(shè)置
- go version 可以查看二進(jìn)制文件的編譯 go 版本
- go build 的參數(shù) trimpath 可以二進(jìn)制文件中的文件系統(tǒng)路徑以提高 build 效率梗脾;-tags 支持多個(gè)編譯選項(xiàng)
- go generate 增加 generate build 選項(xiàng)
Compiler Toolchain
主要改進(jìn)在逃逸分析上更加準(zhǔn)確。因?yàn)楹瘮?shù)棧幀上的變量會隨著函數(shù)調(diào)用結(jié)束而釋放盹靴,所以這可能會導(dǎo)致之前運(yùn)行 OK 的程序出錯(cuò)(比如使用 unsafe 包導(dǎo)致之前誤診斷炸茧,這也是一個(gè)不要使用 unsafe 包的原因)。如果要保持之前的行為可以設(shè)置變量:go build -gcflags=all=-newescape=false
Assembly
支持 ARM v8.1 引入的原子指令Gofmt
支持格式化前面說到的數(shù)字格式稿静。比如:0B1010
梭冠,0XabcDEF
,0O660
改备,1.2E3
控漠,and01i
經(jīng)過 fmt 之后得到0b1010
,0xabcDEF
,0o660
盐捷,1.2e3
偶翅,and1i
。-
godoc
從主包中移除碉渡,如果要使用聚谁,需要單獨(dú)安裝go get golang.org/x/tools/cmd/godoc godoc
Runtime
Out of range 的 panic 信息會包含 index 和 cap 的信息。 Defer 的性能提升 30%滞诺,defer的性能消耗可以參考:尼不要逗了:深入理解 Go 語言 defer形导,Runtime 歸還給 OS 的內(nèi)存策略會更激進(jìn)(原文是 aggressive,我理解這里的激進(jìn)的意思大概是有空閑的就還給你习霹,相比之前會保留一段時(shí)間)朵耕。但是由于很多操作系統(tǒng)對內(nèi)存的回收都是惰性的,所以 Runtime 這個(gè)地方的改變可能并不會導(dǎo)致進(jìn)程的實(shí)際使用的物理內(nèi)存顯著減少序愚,除非系統(tǒng)內(nèi)存不足憔披,主動回收。
三爸吮、標(biāo)準(zhǔn)庫 變動
1)errors包(Error Wraping芬膝,包裝錯(cuò)誤)
支持 wrapping,fmt.Errorf 增加 %w 格式符形娇,errors 包增加三個(gè)函數(shù)(Unwrap锰霜、Is、As
)
-
errors.Unwrap
函數(shù)桐早,原型func Unwrap(err error) error
癣缅,功能:- 對 err 進(jìn)行斷言,看它是否實(shí)現(xiàn)了 Unwrap 方法哄酝,如果是友存,調(diào)用它的 Unwrap 方法,否則陶衅,返回 nil屡立。源碼如下
func Unwrap(err error) error { // 判斷 err 是否實(shí)現(xiàn) Unwrap 函數(shù),也就是是否 是 wrapping error u, ok := err.(interface { Unwrap() error }) // 如果不是搀军,返回nil if !ok { return nil } // 否則則調(diào)用該 error 值的Unwrap方法返回被嵌套的error return u.Unwrap() }
errors.Is
函數(shù)膨俐,原型func Is(err, target error) bool
,功能:
- 如果
err
和target
是同一個(gè)罩句,那么返回true
- 如果 err 有實(shí)現(xiàn) Is 比較方法焚刺,則使用 err的Is 方法來比較,如果err的Is返回為true门烂,則返回true乳愉,否則繼續(xù) error.Is 的比較
- 如果
err
是一個(gè)wrap error,target
也包含在這個(gè)嵌套error鏈中的話,那么也返回true
。
很簡單的一個(gè)函數(shù)匾委,要么咱倆相等拖叙,要么err
包含target
,這兩種情況都返回true
赂乐,其余返回false
薯鳍。源碼如下
func Is(err, target error) bool {
if target == nil {
return err == target
}
isComparable := reflectlite.TypeOf(target).Comparable()
// for循環(huán),把 err 錯(cuò)誤鏈一層層通過剝開挨措,一個(gè)個(gè)比較挖滤,找到就返回true
for {
if isComparable && err == target {
return true
}
// 這里意味著你可以自定義 error 的Is方法,實(shí)現(xiàn)自己的比較代碼
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
return true
}
// 剝開一層浅役,返回被嵌套的err
if err = Unwrap(err); err == nil {
return false
}
}
}
}
為什么需要 Is 函數(shù)斩松?
在 Go 1.13 之前沒有 wapping error 的時(shí)候,我們判斷 error 是不是同一個(gè) error 可以使用如下方法:
if err == os.ErrExist
這樣我們就可以通過判斷來做一些事情觉既。但是有了 Is 方法后惧盹,我們可以進(jìn)行更復(fù)雜的比較了
-
errors.As
函數(shù),原型func As(err error, target interface{}) bool
瞪讼,功能:
- 如果 target 為 nil 或者 nil 指針钧椰,或者 不為接口 且 沒有實(shí)現(xiàn) error接口 的話,會 panic
- 從 err 錯(cuò)誤鏈里找到和 target 相等的并設(shè)置 target 所指向的變量符欠,返回 true嫡霞,否則返回 false
func As(err error, target interface{}) bool {
// 一些判斷,保證 target 希柿,這里是不能為 nil
if target == nil {
panic("errors: target cannot be nil")
}
val := reflectlite.ValueOf(target)
typ := val.Type()
// 這里確保 target 必須是一個(gè)非 nil 指針
if typ.Kind() != reflectlite.Ptr || val.IsNil() {
panic("errors: target must be a non-nil pointer")
}
// 這里確保 target 是一個(gè)接口或者實(shí)現(xiàn)了 erorr 接口
if e := typ.Elem(); e.Kind() != reflectlite.Interface && !e.Implements(errorType) {
panic("errors: *target must be interface or implement error")
}
targetType := typ.Elem()
for err != nil {
// 關(guān)鍵部分诊沪,反射判斷是否可以被賦予,如果可以賦予并且返回 true
if reflectlite.TypeOf(err).AssignableTo(targetType) {
val.Elem().Set(reflectlite.ValueOf(err))
return true
}
// 這里意味著你可以自定義 error 的As方法曾撤,實(shí)現(xiàn)自己的類型斷言代碼
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
return true
}
err = Unwrap(err)
}
return false
}
剩下一個(gè) %w 是什么呢端姚?打開源碼
// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// If the format specifier includes a %w verb with an error operand,
// the returned error will implement an Unwrap method returning the operand. It is
// invalid to include more than one %w verb or to supply it with an operand
// that does not implement the error interface. The %w verb is otherwise
// a synonym for %v.
// Errorf根據(jù)格式說明符設(shè)置格式,并以
//滿足錯(cuò)誤的值挤悉。
//
//如果格式說明符包含帶有錯(cuò)誤操作數(shù)的%w動詞寄锐,
//返回的錯(cuò)誤將實(shí)現(xiàn)Unwrap方法,返回操作數(shù)尖啡。它是
//包含多個(gè)%w動詞或?yàn)槠涮峁┎僮鲾?shù)無效
//沒有實(shí)現(xiàn)錯(cuò)誤接口的代碼。 %w動詞否則為
//%v的同義詞剩膘。
func Errorf(format string, a ...interface{}) error {
p := newPrinter()
p.wrapErrs = true
p.doPrintf(format, a)
s := string(p.buf)
var err error
if p.wrappedErr == nil {
err = errors.New(s)
} else {
err = &wrapError{s, p.wrappedErr}
}
p.free()
return err
}
type wrapError struct {
msg string
err error
}
func (e *wrapError) Error() string {
return e.msg
}
func (e *wrapError) Unwrap() error {
return e.err
}
從源碼中我們可以得知是這樣的衅斩,傳入對應(yīng) %w 的值是一個(gè)實(shí)現(xiàn)了 error 接口的值,則返回一個(gè)帶 實(shí)現(xiàn)了Unwrap的error值怠褐,否則 %w 的效果等于 %v畏梆。
2)crypto/ed25519 包
package crypto/ed25519 實(shí)現(xiàn)了之前在 package golang.org/x/crypto/ed25519 中實(shí)現(xiàn)的Ed25519 算法。
3)reflect包
reflect
標(biāo)準(zhǔn)庫包中將為Value
類型添加一個(gè)IsZero
方法,用來判斷一個(gè)值是否為零值奠涌。
四宪巨、語言 spec 方面改動
主要集中在這個(gè) Proposal:golang/proposal,主要是一些數(shù)字的表示方面溜畅,包括:
- 使用 0b/0B 開頭來表示二進(jìn)制數(shù)(賦值給變量之后捏卓,會被轉(zhuǎn)換程十進(jìn)制,還是int慈格、float等類型)
- 使用 0o/0O(前面是數(shù)字零怠晴,后面是字母o)表示八進(jìn)制數(shù)(如上)
- 使用0x/0X 開頭來表征十六進(jìn)制數(shù)(如上)
- 使用 i 來表示復(fù)數(shù)
- 可使用下劃線 _ 來作為數(shù)字分割
右移位操作的 unsign 限制移除,Proposal: golang/proposal浴捆,移位操作中的右移位將允許為有符號整數(shù)蒜田,在1.13之前的Go 版本,<< 右邊必須為無符號類型確定整數(shù)或者可以表示成uint
值的類型不確定值选泻,在1.13之后冲粤,加上了有符號整數(shù)的非負(fù)值,如果是負(fù)正數(shù)页眯,將panic
五梯捕、庫平臺支持
- AIX:aix平臺支持 cgo
- Android:兼容 Android Q
- Darwin:Go 1.13 支持需要macOS 版本 10.11 El Capition 及以上
- FreeBSD:FreeBSD 11.2及以上
- Illumos:編譯選項(xiàng)
GOOS==illumos
支持 - NetBSD:支持 NetBSD on ARM64
- OpenBSD:支持 OpenBSD on ARM64
- Windows:底層要求 Windows 7
視頻資源
- 【Go 夜讀】#58 What's new in Go 1.13?,可能是我水平不夠餐茵,聽著很蒙感覺