Golang 数据结构:掌握 Go 语言的核心数据结构

# Golang 数据结构:掌握 Go 语言的核心数据结构

## 数组(Array)

### 数组的定义

数组是一种固定长度的、相同类型元素的集合。

“`go
// 声明数组
var arr [5]int

// 初始化数组
arr = [5]int{1, 2, 3, 4, 5}

// 自动推断长度
arr = […]int{1, 2, 3, 4, 5}

// 部分初始化
arr = [5]int{1, 2}
“`

### 数组的操作

“`go
// 访问元素
fmt.Println(arr[0]) // 输出:1

// 修改元素
arr[0] = 10

// 遍历数组
for i := 0; i < len(arr); i++ { fmt.Println(arr[i]) } // 使用 range 遍历 for index, value := range arr { fmt.Println(index, value) } ``` ### 数组的特性 - 数组的长度是固定的,一旦声明就不能改变 - 数组是值类型,赋值或传递给函数时会复制整个数组 - 数组的长度是其类型的一部分,`[5]int` 和 `[10]int` 是不同的类型 ## 切片(Slice) ### 切片的定义 切片是对数组的引用,是一种可变长度的数据结构。 ```go // 声明切片 var slice []int // 从数组创建切片 arr := [5]int{1, 2, 3, 4, 5} slice = arr[1:4] // 包含索引 1,不包含索引 4 // 使用 make 创建切片 slice = make([]int, 5) // 长度为 5,容量为 5 slice = make([]int, 5, 10) // 长度为 5,容量为 10 // 直接初始化切片 slice = []int{1, 2, 3, 4, 5} ``` ### 切片的操作 #### 添加元素 ```go // 添加单个元素 slice = append(slice, 6) // 添加多个元素 slice = append(slice, 7, 8, 9) // 添加另一个切片 slice = append(slice, []int{10, 11, 12}...) ``` #### 复制切片 ```go // 复制切片 src := []int{1, 2, 3} dest := make([]int, len(src)) copy(dest, src) ``` #### 切片的长度和容量 ```go // 获取长度 length := len(slice) // 获取容量 capacity := cap(slice) ``` ### 切片的特性 - 切片是引用类型,指向底层数组 - 切片的长度可以动态改变 - 切片的容量是指从切片的第一个元素到底层数组末尾的元素个数 - 当切片容量不足时,`append` 操作会创建一个新的底层数组 ## 映射(Map) ### 映射的定义 映射是一种键值对的集合,类似于其他语言中的字典或哈希表。 ```go // 声明映射 var m map[string]int // 使用 make 创建映射 m = make(map[string]int) // 直接初始化映射 m = map[string]int{ "apple": 1, "banana": 2, "cherry": 3, } ``` ### 映射的操作 #### 添加或修改元素 ```go m["apple"] = 5 // 如果键存在则修改,不存在则添加 ``` #### 获取元素 ```go // 获取元素 value, ok := m["apple"] if ok { fmt.Println("Value:", value) } else { fmt.Println("Key not found") } // 直接获取(如果键不存在,返回零值) value := m["orange"] ``` #### 删除元素 ```go delete(m, "apple") ``` #### 遍历映射 ```go for key, value := range m { fmt.Println(key, value) } ``` ### 映射的特性 - 映射是引用类型 - 映射的键必须是可比较的类型(如字符串、数字、布尔值等) - 映射的值可以是任意类型 - 映射是无序的,遍历顺序不固定 ## 结构体(Struct) ### 结构体的定义 结构体是一种复合数据类型,用于组合多个不同类型的字段。 ```go type Person struct { Name string Age int Address string } // 嵌套结构体 type Address struct { Street string City string Country string } type Person struct { Name string Age int Address Address } ``` ### 结构体的使用 ```go // 创建结构体实例 p := Person{ Name: "John", Age: 30, Address: "New York", } // 访问结构体字段 fmt.Println(p.Name) fmt.Println(p.Age) // 修改结构体字段 p.Age = 31 // 结构体作为参数 func printPerson(p Person) { fmt.Println(p.Name, p.Age) } // 结构体指针作为参数 func updateAge(p *Person, age int) { p.Age = age } ``` ### 结构体方法 ```go // 值接收者方法 func (p Person) GetName() string { return p.Name } // 指针接收者方法 func (p *Person) SetAge(age int) { p.Age = age } ``` ## 接口(Interface) ### 接口的定义 接口是一种抽象类型,定义了一组方法签名,任何类型只要实现了这些方法,就被认为实现了该接口。 ```go type Animal interface { Speak() string Move() string } ``` ### 接口的实现 ```go type Dog struct { Name string } func (d Dog) Speak() string { return "Woof!" } func (d Dog) Move() string { return "Run" } type Cat struct { Name string } func (c Cat) Speak() string { return "Meow!" } func (c Cat) Move() string { return "Walk" } ``` ### 接口的使用 ```go func MakeAnimalSpeak(a Animal) { fmt.Println(a.Speak()) } func MakeAnimalMove(a Animal) { fmt.Println(a.Move()) } // 使用接口 dog := Dog{Name: "Buddy"} cat := Cat{Name: "Whiskers"} MakeAnimalSpeak(dog) // 输出: Woof! MakeAnimalSpeak(cat) // 输出: Meow! MakeAnimalMove(dog) // 输出: Run MakeAnimalMove(cat) // 输出: Walk ``` ### 接口的特性 - 接口是隐式实现的,不需要显式声明 - 一个类型可以实现多个接口 - 接口可以嵌套 - 空接口 `interface{}` 可以接受任何类型的值 ## 通道(Channel) ### 通道的定义 通道是用于在 goroutine 之间传递数据的管道。 ```go // 声明通道 var ch chan int // 使用 make 创建通道 ch = make(chan int) // 创建带缓冲区的通道 ch = make(chan int, 10) ``` ### 通道的操作 #### 发送数据 ```go ch <- 10 // 发送 10 到通道 ``` #### 接收数据 ```go // 接收数据 value := <-ch // 非阻塞接收 value, ok := <-ch if ok { fmt.Println("Received:", value) } else { fmt.Println("Channel closed") } ``` #### 关闭通道 ```go close(ch) ``` #### 遍历通道 ```go // 遍历通道中的所有数据 for value := range ch { fmt.Println(value) } ``` ### 通道的特性 - 通道是引用类型 - 通道默认是无缓冲的,发送和接收操作会阻塞 - 带缓冲的通道在缓冲区满时发送会阻塞,在缓冲区空时接收会阻塞 - 关闭通道后,不能再发送数据,但可以继续接收数据 ## 总结 本文介绍了 Go 语言中的核心数据结构,包括数组、切片、映射、结构体、接口和通道。这些数据结构是 Go 语言的基础,掌握它们对于编写高效、清晰的 Go 代码至关重要。在实际开发中,我们需要根据具体场景选择合适的数据结构,以达到最佳的性能和代码可读性。

Scroll to Top