Go 中切片的 Contains 方法:如何检查而不抓狂

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

“contains 在哪?”——Go 新手的第一大痛点

\n\n

想象一下:你用 Go 编程,有一个字符串切片 ["python", "go", "rust", "javascript"],需要检查其中是否包含语言 "go"。如果你来自 Python、Ruby 或 JavaScript,你会下意识地写下 slice.contains("go")——然后得到一个红色的编译错误。“这算什么?”你想。“任何一个正经的集合都应该有 contains 方法!”

\n\n

冷静,保持冷静。Go 确实没有为切片内置 contains 方法。这不是 bug,而是特性。语言设计者认为,一个通用的函数无法覆盖所有情况(字符串、数字、结构体的比较),因此将实现留给了程序员。听起来很吓人,但实际上既简单又优雅。在本文中,我们将探讨如何为 Go 切片编写 contains 方法,分析性能、常见陷阱,并提供现成的解决方案。

\n\n

为什么 Go 没有为切片提供 contains 方法?

\n

Go 是一门极简的语言。在 1.18 版本之前,它没有泛型和方法重载。切片不是带有方法的对象,而是一种数据结构:指向数组的指针、长度和容量。Go 的设计者认为 contains 函数应该是显式的,以便程序员始终清楚比较是如何进行的。这减少了 bug 的数量,并使代码更具可预测性。

\n

此外,切片的 contains 方法始终是线性搜索(O(n)),如果你期望 O(1) 的性能,那么你选错了数据结构(应该使用 map)。Go 不想掩盖这种复杂性。

\n\n

Go 中最简单的切片 contains 方法(手动遍历)

\n

让我们为字符串切片编写一个 contains 方法。这是你在任何生产代码中都会看到的经典写法:

\n\n
package main\n\nimport "fmt"\n\n// Contains 检查元素是否在字符串切片中\nfunc Contains(slice []string, target string) bool {\n    for _, item := range slice {\n        if item == target {\n            return true\n        }\n    }\n    return false\n}\n\nfunc main() {\n    languages := []string{"python", "go", "rust", "javascript"}\n    fmt.Println(Contains(languages, "go"))       // true\n    fmt.Println(Contains(languages, "csharp"))   // false\n}
\n\n

很简单:遍历切片,将每个元素与目标值进行比较。如果找到,返回 true,否则返回 false。注意: == 运算符适用于字符串、数字、布尔值和指针。对于结构体或嵌套切片(切片中的切片),这种方法不适用。

\n\n

数字的 Contains 方法

\n

对于整数切片,代码几乎相同:

\n\n
func ContainsInt(slice []int, target int) bool {\n    for _, v := range slice {\n        if v == target {\n            return true\n        }\n    }\n    return false\n}\n\nfunc main() {\n    numbers := []int{10, 20, 30, 40, 50}\n    fmt.Println(ContainsInt(numbers, 30)) // true\n    fmt.Println(ContainsInt(numbers, 99)) // false\n}
\n\n

不方便?是的。但这就是 Go——显式和简单高于一切。

\n\n

Go 中通用的切片 contains 方法(泛型,Go 1.18+)

\n

随着 Go 1.18 的发布,语言中引入了泛型。现在你可以为任何支持比较的类型编写一个 contains 函数:

\n\n
package main\n\nimport "fmt"\n\n// ContainsGeneric 适用于任何 comparable 类型\nfunc ContainsGeneric[T comparable](slice []T, target T) bool {\n    for _, item := range slice {\n        if item == target {\n            return true\n        }\n    }\n    return false\n}\n\nfunc main() {\n    strs := []string{"a", "b", "c"}\n    ints := []int{1, 2, 3}\n    floats := []float64{1.1, 2.2, 3.3}\n\n    fmt.Println(ContainsGeneric(strs, "b"))   // true\n    fmt.Println(ContainsGeneric(ints, 5))     // false\n    fmt.Println(ContainsGeneric(floats, 2.2)) // true\n}
\n\n

comparable 约束意味着该类型支持 == 和

博客

书籍推荐