Golang仅用两种内置数据结构的核心设计思想
Golang仅用两种内置数据结构的核心设计思想
-
Go 仅提供了切片和映射这两种内置数据结构。这比 C 语言(仅数组)多,但比 Python、C++ 和 Swift 少。我认为这很棒,它使得大家的代码看起来都有些相似。但我仍然想知道,设计这两种内置数据结构背后的理念是什么。
-
当我想要检查一个自定义结构体类型的键是否存在于映射中时,为什么它不需要某种哈希或相等接口?例如,如果我要对自定义结构体的切片进行排序,我将需要定义排序所需的 Len、Less、Swap 方法。
谢谢
package main
import (
"fmt"
)
type K struct {
name string
num int
}
func main() {
d := map[K]struct{}{}
d[K{"ccc", 3}] = struct{}{}
d[K{"bbb", 2}] = struct{}{}
d[K{"aaa", 1}] = struct{}{}
k := K{"bbb", 2}
v, ok := d[k]
fmt.Println(v, ok) //true
}
更多关于Golang仅用两种内置数据结构的核心设计思想的实战教程也可以访问 https://www.itying.com/category-94-b0.html
这是正确的,但这取决于结构体的字段。如果你添加了一个不可比较的字段,那么整个结构体就不再可比较。
感谢Christoph,
我刚发现这两个运算符是为结构体定义的,但小于或大于运算符则不是。不过在C++中,结构体默认是不可比较的。
type K struct {
name string
num int
}
func main() {
k1 := K{"bbb", 2}
k2 := K{"bbb", 2}
fmt.Println("k1 == k2", k1 == k2) //true
fmt.Println("k1 != k2", k1 != k2) //false
// fmt.Println("k1 < k2", k1 < k2) //not defined
// fmt.Println("k1 > k2", k1 > k2) //not defined
}
-
我认为这里的主要设计原则是极简主义。基本类型、数组/切片、映射、结构体和接口几乎就是你构建更复杂数据结构所需的全部。
我不太清楚Python或Swift除了映射和(动态)数组之外还提供了哪些类型,但我敢打赌,这些类型可以毫不费力地用Go的内置类型来表达。因此,没有令人信服的理由将它们包含在核心语言中。
-
映射的键必须是可比较的类型。也就是说,只有定义了
==和!=操作符的类型才能用作映射键。因此,不需要额外的语言构造来测试一个键是否存在于映射中。另一方面,切片可以容纳任何类型的数据。与映射不同,切片没有理由将元素类型限制为可排序类型。因此,如果你想对具有自定义元素类型的切片进行排序,你必须实现自己的排序算法。Len/Less/Swap接口可以帮助你做到这一点。
// 示例:实现 sort.Interface 进行自定义排序
type ByLength []string
func (s ByLength) Len() int {
return len(s)
}
func (s ByLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s ByLength) Less(i, j int) bool {
return len(s[i]) < len(s[j])
}
Go语言仅提供切片和映射作为内置数据结构,这体现了其“简单性”和“实用性”的设计哲学。切片提供了动态数组的能力,映射提供了键值对存储,这两种结构覆盖了大多数实际开发场景。这种设计减少了语言复杂性,同时通过标准库的container包(如list、heap)支持其他数据结构,保持了灵活性。
关于映射键的检查,Go要求键类型必须是可比较的(comparable),这意味着类型必须支持==和!=操作。对于自定义结构体,如果其所有字段都是可比较的,那么结构体本身也是可比较的,因此可以直接用作映射键,无需显式实现哈希或相等接口。这是因为Go在编译时自动为可比较类型生成了必要的比较逻辑。例如:
package main
import "fmt"
type Key struct {
Name string
ID int
}
func main() {
m := make(map[Key]string)
k1 := Key{"Alice", 1}
m[k1] = "value1"
k2 := Key{"Alice", 1}
value, exists := m[k2] // 自动比较k1和k2的字段值
fmt.Println(value, exists) // 输出: value1 true
}
相比之下,排序需要实现sort.Interface,因为排序规则(如Less方法)是业务逻辑相关的,无法由编译器自动推断。映射键的比较是值等性检查,而排序涉及顺序逻辑,这解释了为什么两者设计不同。

