Go1.18 新特性:新增好用的 Cut 方法
大家好,我是煎魚。
在各種寫業務代碼的時候,大家會常常要處理字符串的內容。常見的像是用郵箱登陸賬號,如果是:eddycjy@gmail.com,那就得根據 @ 來切割,分別取出前和后,來識別用戶名和郵箱地址。
這種需求,在 Go 里寫起來方便嗎?今天就由煎魚帶大家了解。
背景
重復代碼
無獨有偶,Ainar Garipov 在許多項目中遇到了前面我們所提的切割需求。
例如:
idx = strings.Index(username, "@")
if idx != -1 {
name = username[:idx]
} else {
name = username
}
又或是:
idx = strings.LastIndex(address, "@")
if idx != -1 {
host = address[idx+1:]
} else {
host = address
}
經常要反復寫一些繁瑣的代碼,提案提出者表示不愉快。
新提案
實施內容
建議新增 Cut 方法到 strings 標準庫:
func Cut(s, sep string) (before, after string, found bool) {
if i := Index(s, sep); i >= 0 {
return s[:i], s[i+len(sep):], true
}
return s, "", false
}
同步也要在 bytes 標準庫:
func Cut(s, sep []byte) (before, after []byte, found bool)
這樣一來,就可以從原本的:
eq := strings.IndexByte(rec, '=')
if eq == -1 {
return "", "", s, ErrHeader
}
k, v = rec[:eq], rec[eq+1:]
變成:
k, v, ok = strings.Cut(rec, "=")
if !ok {
return "", "", s, ErrHeader
}
寫法上會更優雅,在復雜的場景下會更具可讀性和抽象級別。
接受原因
可能就有小伙伴會吐槽了,Go 居然只為了節省 1 行代碼,就搞了個新函數,這還是大道至簡嗎?
實際上,在官方團隊(Russ Cox)介入后,他對 Go 主倉庫進行了分析,搜索了相關類似函數的使用:
- strings.Index。
- strings.IndexByte。
- strings.IndexRune。
統計后,轉換為了可以使用 strings.Cut 的用法,在例子和測試數據之外有 311 個索引調用。
排除了一些確實不需要的,剩下 285 個調用。在這些調用中,有 221 次是最好寫成 Cut 方法的,能更優雅。
也就是說,有現有的 Go 代碼中,有 77% 可以用新增的 Cut 函數寫得更清楚,可讀性和抽象可以做得更好。
Go 主倉庫確實存在如此重復的代碼,他認為這也是非常不可思議的!
總結
Go1.18 的新特性中,Cut 雖然只是新增了一個方法,看上去無傷大雅。
但類似 Cut 方法的用法,在 Go 的主版本中其實已經被發明了兩次。
該新方法的出現,可以同時取代并簡化四個不同的標準庫函數:Index、IndexByte、IndexRune 和 SplitN 中的絕大部分用法。
由于這些原因,最終將 Cut 添加到標準庫中。
你覺得怎么樣?:)
參考
bytes, strings: add Cut