Go1.18 快讯:新增的 Cut 函数太方便了

大家好,我是 polarisxu。

在编程中,字符串使用是最频繁的。Go 语言对字符串相关的操作也提供了大量的 API,一方面,字符串可以向普通 slice 一样进行相关操作;另一方面,标准库专门提供了一个包 strings 进行字符串的操作。

01 strings.Index 系列函数

假如有一个这样的需求:从 192.168.1.1:8080 中获取 ip 和 port。

我们一般会这么实现:

addr := "192.168.1.1:8080"
pos := strings.Index(addr, ":")
if pos == -1 {
  panic("非法地址")
}
ip, port := addr[:pos], addr[pos+1:]

实际项目中,pos == -1 时应该返回 error

此处忽略通过 net.TCPAddr 方式得到,主要在于讲解字符串处理。

strings 包中,Index 相关函数有好几个:

func Index(s, substr string) int
func IndexAny(s, chars string) int
func IndexByte(s string, c byte) int
func IndexFunc(s string, f func(rune) bool) int
func IndexRune(s string, r rune) int
func LastIndex(s, substr string) int
func LastIndexAny(s, chars string) int
func LastIndexByte(s string, c byte) int
func LastIndexFunc(s string, f func(rune) bool) int

Go 官方统计了 Go 源码中使用相关函数的代码:

  • 311 Index calls outside examples and testdata.
  • 20 should have been Contains
  • 2 should have been 1 call to IndexAny
  • 2 should have been 1 call to ContainsAny
  • 1 should have been TrimPrefix
  • 1 should have been HasSuffix

相关需求是这么多,而 Index 显然不是处理类似需求最好的方式。于是 Russ Cox 提议,在 strings 包中新增一个函数 Cut,专门处理类似的常见。

02 新增的 Cut 函数

Cut 函数的签名如下:

func Cut(s, sep string) (before, after string, found bool)

将字符串 s 在第一个 sep 处切割为两部分,分别存在 before 和 after 中。如果 s 中没有 sep,返回 s,"",false

根据 Russ Cox 的统计,Go 源码中 221 处使用 Cut 会更好。

针对上文提到的需求,改用 Cut 函数:

addr := "192.168.1.1:8080"
ip, port, ok := strings.Cut(addr, ":")

是不是很清晰?!

这是又一个改善生活质量的优化。

针对该函数,官方提供了如下示例:

package main

import (
	"fmt"
	"strings"
)

func main() {
	show := func(s, sep string) {
		before, after, found := strings.Cut(s, sep)
		fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
	}
	show("Gopher", "Go")
	show("Gopher", "ph")
	show("Gopher", "er")
	show("Gopher", "Badger")
}

// Output:
/*
Cut("Gopher", "Go") = "", "pher", true
Cut("Gopher", "ph") = "Go", "er", true
Cut("Gopher", "er") = "Goph", "", true
Cut("Gopher", "Badger") = "Gopher", "", false
*/

03 总结

从 PHP 转到 Go 的朋友,肯定觉得 Go 标准库应该提供更多便利函数,让生活质量更好。在 Go 社区这么多年,也确实听到了不少这方面的声音。

但 Go 官方不会轻易增加一个功能。就 Cut 函数来说,官方做了详细调研、说明,具体可以参考这个 issue:bytes, strings: add Cut ,可见 bytes 同样的增加了 Cut 函数。

有人提到,为什么不增加 LastCut?Russ Cox 的解释是,LastIndex 的调用次数明显少于 Index,因此暂不提供 LastCut。

做一个决定,不是瞎拍脑袋的~