Go1.18 新特性:新增好用的 Cut 方法

煎魚發表於2022-01-31

大家好,我是煎魚。

在各種寫業務程式碼的時候,大家會常常要處理字串的內容。常見的像是用郵箱登陸賬號,如果是: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 新增到標準庫中。

你覺得怎麼樣?:)

若有任何疑問歡迎評論區反饋和交流,最好的關係是互相成就,各位的點贊就是煎魚創作的最大動力,感謝支援。

文章持續更新,可以微信搜【腦子進煎魚了】閱讀,本文 GitHub github.com/eddycjy/blog 已收錄,學習 Go 語言可以看 Go 學習地圖和路線,歡迎 Star 催更。

參考

相關文章