编程语言 go golang的核心数据结构介绍 星野暗涌 2026-05-08 2026-07-04 1. 数组(Array) 基本特性
代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" func main () { var arr1 [5 ]int arr2 := [3 ]int {1 , 2 , 3 } arr3 := [...]int {1 , 2 , 3 , 4 } arr4 := arr2 arr4[0 ] = 100 fmt.Println(arr2) fmt.Println(arr4) matrix := [2 ][3 ]int { {1 , 2 , 3 }, {4 , 5 , 6 }, } fmt.Println(matrix[1 ][2 ]) }
使用场景
长度固定且已知的小型数据集
需要栈上分配避免堆内存开销
作为切片的底层存储
2. 切片(Slice) 底层结构 切片是对数组的抽象,其底层结构为:
1 2 3 4 5 type slice struct { array unsafe.Pointer len int cap int }
核心操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package mainimport "fmt" func main () { var s1 []int s2 := []int {} s3 := make ([]int , 5 , 10 ) s := []int {1 , 2 , 3 } s = append (s, 4 , 5 ) s = append (s, []int {6 , 7 }...) sub := s[1 :4 ] sub[0 ] = 100 fmt.Println(s) demonstrateGrowth() } func demonstrateGrowth () { s := make ([]int , 0 , 4 ) for i := 0 ; i < 10 ; i++ { s = append (s, i) fmt.Printf("len=%d cap=%dn" , len (s), cap (s)) } }
深拷贝 vs 浅拷贝 1 2 3 4 5 6 7 8 9 s1 := []int {1 , 2 , 3 } s2 := s1 s2[0 ] = 100 s3 := make ([]int , len (s1)) copy (s3, s1)s3[0 ] = 200
陷阱与最佳实践 ⚠️ 内存泄漏风险
3. 映射(Map) 底层实现 Go 的 map 采用哈希表 + 拉链法 解决冲突:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type hmap struct { count int B uint8 buckets unsafe.Pointer oldbuckets unsafe.Pointer } type bmap struct { tophash [8 ]uint8 keys [8 ]keytype values [8 ]valuetype overflow *bmap }
基本用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport "fmt" func main () { var m1 map [string ]int m2 := map [string ]int {} m3 := make (map [string ]int , 10 ) m := map [string ]int { "Alice" : 25 , "Bob" : 30 , } m["Charlie" ] = 35 m["Alice" ] = 26 delete (m, "Bob" ) if age, ok := m["David" ]; ok { fmt.Println(age) } else { fmt.Println("Key not found" ) } for k, v := range m { fmt.Printf("%s: %dn" , k, v) } }
并发安全 🔒 map 不是并发安全的
扩容机制
4. 通道(Channel) ⚠️需要结合并发与协程
核心概念 通道是 Go 并发编程的核心,实现了 CSP (Communicating Sequential Processes)模型。
底层结构 1 2 3 4 5 6 7 8 9 10 11 type hchan struct { qcount uint dataqsiz uint buf unsafe.Pointer elemsize uint16 sendx uint recvx uint recvq waitq sendq waitq lock mutex }
三种类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package mainimport ( "fmt" "time" ) func main () { ch1 := make (chan int ) go func () { ch1 <- 42 }() fmt.Println(<-ch1) ch2 := make (chan int , 3 ) ch2 <- 1 ch2 <- 2 ch2 <- 3 fmt.Println(<-ch2) ch3 := make (chan int ) go producer(ch3) consumer(ch3) } func producer (ch chan <- int ) { for i := 0 ; i < 5 ; i++ { ch <- i } close (ch) } func consumer (ch <-chan int ) { for val := range ch { fmt.Println(val) } }
高级用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package mainimport ( "fmt" "time" ) func main () { ch1 := make (chan string ) ch2 := make (chan string ) go func () { time.Sleep(100 * time.Millisecond) ch1 <- "from ch1" }() go func () { time.Sleep(50 * time.Millisecond) ch2 <- "from ch2" }() select { case msg1 := <-ch1: fmt.Println(msg1) case msg2 := <-ch2: fmt.Println(msg2) case <-time.After(200 * time.Millisecond): fmt.Println("timeout" ) } select { case msg := <-ch1: fmt.Println(msg) default : fmt.Println("no message" ) } ch := make (chan int , 2 ) ch <- 1 ch <- 2 close (ch) for { val, ok := <-ch if !ok { fmt.Println("channel closed" ) break } fmt.Println(val) } }
最佳实践 ✅ 通道使用原则
5. 结构体(Struct) 内存布局与对齐(和C语言的内存对齐机制一致) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport ( "fmt" "unsafe" ) type BadStruct struct { a bool b int64 c bool } type GoodStruct struct { b int64 a bool c bool } func main () { fmt.Println(unsafe.Sizeof(BadStruct{})) fmt.Println(unsafe.Sizeof(GoodStruct{})) }
嵌入与组合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package mainimport "fmt" type Animal struct { Name string } func (a Animal) Speak() { fmt.Println(a.Name, "makes a sound" ) } type Dog struct { Animal Breed string } func (d Dog) Speak() { fmt.Println(d.Name, "barks" ) } func main () { d := Dog{ Animal: Animal{Name: "Buddy" }, Breed: "Golden Retriever" , } d.Speak() d.Animal.Speak() fmt.Println(d.Name) }
标签(Tag)与反射 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "encoding/json" "fmt" "reflect" ) type User struct { ID int `json:"id" db:"user_id"` Name string `json:"name" validate:"required"` Password string `json:"-"` } func main () { u := User{ID: 1 , Name: "Alice" , Password: "secret" } data, _ := json.Marshal(u) fmt.Println(string (data)) t := reflect.TypeOf(u) field, _ := t.FieldByName("ID" ) fmt.Println(field.Tag.Get("json" )) fmt.Println(field.Tag.Get("db" )) }
6. 接口(Interface) 底层结构 1 2 3 4 5 6 7 8 9 10 11 type eface struct { _type *_type data unsafe.Pointer } type iface struct { tab *itab data unsafe.Pointer }
动态派发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package mainimport "fmt" type Shape interface { Area() float64 } type Circle struct { Radius float64 } func (c Circle) Area() float64 { return 3.14 * c.Radius * c.Radius } type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func printArea (s Shape) { fmt.Printf("Area: %.2fn" , s.Area()) } func main () { c := Circle{Radius: 5 } r := Rectangle{Width: 4 , Height: 6 } printArea(c) printArea(r) var s Shape = c if circle, ok := s.(Circle); ok { fmt.Println("Radius:" , circle.Radius) } switch v := s.(type ) { case Circle: fmt.Println("This is a circle with radius" , v.Radius) case Rectangle: fmt.Println("This is a rectangle" ) } }
7. 性能对比与选型 基准测试示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport "testing" func BenchmarkArrayAccess (b *testing.B) { arr := [1000 ]int {} for i := 0 ; i < b.N; i++ { _ = arr[500 ] } } func BenchmarkSliceAccess (b *testing.B) { slice := make ([]int , 1000 ) for i := 0 ; i < b.N; i++ { _ = slice[500 ] } } func BenchmarkMapAccess (b *testing.B) { m := make (map [int ]int ) for i := 0 ; i < 1000 ; i++ { m[i] = i } b.ResetTimer() for i := 0 ; i < b.N; i++ { _ = m[500 ] } }
选型建议
数据结构
时间复杂度
适用场景
Array
O(1) 访问
固定长度、栈分配
Slice
O(1) 访问、O(1) 均摊追加
动态数组、大部分场景
Map
O(1) 均摊查找
键值存储、快速查找
Channel
O(1) 发送/接收
并发通信、任务队列
总结 Go 的数据结构设计遵循简洁高效 的哲学:
切片 是最常用的动态数组,理解扩容机制和共享语义至关重要
映射 提供高效键值存储,注意并发安全问题
通道 是并发的第一公民,优先使用通道而非共享内存
接口 实现多态和解耦,动态派发有一定性能开销
结构体 内存对齐影响性能,合理排列字段可节省空间
深入理解这些数据结构的底层实现,能帮助你写出更高效、更地道的 Go 代码。
参考资料