试试 go语言 strings包新增 Cut API

510 阅读3分钟

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

2022年3月15日,Go 1.18正式版发布,带来了很多特性,尤其是泛型的支持,带来很多便利,但是今天我们不谈泛型,主要来说说在 Go 1.18版本中,strings 包新增的两个API:Clone 和 Cut,这里我们主要谈一下 Cut 的使用。

Cut 函数的定义如下:

// Cut slices s around the first instance of sep,
// returning the text before and after sep.
// The found result reports whether sep appears in s.
// If sep does not appear in s, cut returns s, "", false.
func Cut(s, sep string) (before, after string, found bool)

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

比如现在有一个需求:从 example.rs@gmail.com 中获取 邮箱名称与 邮箱后缀。在 Go1.18 版本发布之前,我们实现的方式是:

package main

import (
	"fmt"
	"strings"
)

func main() {
	email := "example.rs@gmail.com"
	pos := strings.Index(addr, "@")
    if pos == -1 {
        fmt.Println("非法邮箱地址")
    } else {
        username, suffix := email[:pos], email[pos+1:]
        fmt.Println(username, suffix)
    }
}

而在 Go1.18 版本之后,我们就可以使用 Cut 来实现类似的功能:

package main

import (
	"fmt"
	"strings"
)

func main() {
	addr := "example.rs@gmail.com"
	username, suffix, found := strings.Cut(addr, ":")
	if found {
		fmt.Println(username, suffix)
	} else {
		fmt.Println("非法邮箱地址")
	}
}

我们可以看下Cut的源代码:

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
}

其实,可以看到,源代码的实现其实与我们上面的代码基本类似,只不过比上面写的更加凝练一些。将字符串 s 在第一个 sep 处切割成两部分,分别存储到 before 和 after 中。当字符串 s 中没有 sep时,before 则为 s,after 则为空,found 为false,即 s, "", false。 在用 Cut 时,我们一定得注意,如果 sep 多次出现时,依旧是以第一处为切割,其他的则不予处理,依旧出现在 after 中。

其实,官方提供的示例也很清楚的介绍了 Cut 的用法:

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
*/

可能有人会吐槽,Go 语言为了省一行代码居然出一个新的函数,是否有违Go语言的初衷呢?其实, Russ Cox 在关于 Cut 函数更加详细的阐述了一下理由: image.png 可以看出,除了示例和测试数据之外,有311处索引调用可以使用 strings.Cut 用法。再排除一些确实不需要的剩下285处,而其中221处更加适合使用 Cut 方法的。也就是说,在现有的Go代码中,有77%可以用新增 Cut 方法来更清楚的使用。

更详细的你可以通过此链接去了解, github.com/golang/go/i…

除 strings 标准库之外,bytes 库中同样增加了 Cut 的方法,使用方式也与 strings 类似。