一、数组
数组是一种常见的数据结构,它可以用来存储多个相同类型的数据元素。数组中的元素通常按照一定的顺序进行排列,可以通过索引来访问和操作数组中的元素。在编程中,数组可以用于存储各种类型的数据,如数字、字符、对象等。
例如,我们可以定义一个整数数组来存储学生的成绩,或者定义一个字符串数组来存储学生的姓名。通过数组的索引,我们可以方便地访问和修改数组中的元素。
package main
import "fmt"
// 定义一个学生成绩数组
var scores [5]int
func main() {
// 给数组赋值
scores[0] = 85
scores[1] = 92
scores[2] = 78
scores[3] = 90
scores[4] = 88
// 输出数组元素
for i, score := range scores {
fmt.Printf("学生 %d 的成绩是: %d\n", i+1, score)
}
}
二、切片
切片是一种动态数组,它可以根据需要增长或缩小。与数组不同的是,切片不需要预先指定长度,而是可以在运行时根据需要进行修改。切片通过索引和长度来访问和操作其中的元素。
例如,我们可以使用切片来存储学生的成绩列表,并且可以根据学生人数的变化动态地调整切片的长度。切片还提供了一些方便的操作,如追加元素、删除元素、截取子切片等。
以下是一个使用 Go 语言操作切片的示例:
package main
import "fmt"
// 定义一个切片
var scores []int
func main() {
// 追加元素到切片
scores = append(scores, 85)
scores = append(scores, 92)
scores = append(scores, 78)
scores = append(scores, 90)
scores = append(scores, 88)
// 输出切片元素
for i, score := range scores {
fmt.Printf("学生 %d 的成绩是: %d\n", i+1, score)
}
}
2.1 切片删除
在 Go 语言中,可以使用切片的一些方法来删除切片中的元素。例如,可以使用copy函数将切片的一部分复制到一个新的切片中,从而实现删除操作。
[1:2]使用规则是左闭右开
以下是一个示例,展示了如何删除切片中的特定元素:
package main
import (
"fmt"
)
// 定义一个切片
var scores = []int{85, 92, 78, 90, 88}
func main() {
// 删除索引为 2 的元素
scores = deleteScore(scores, 2)
// 输出切片元素
fmt.Println(scores)
for i, score := range scores {
fmt.Printf("学生 %d 的成绩是: %d\n", i+1, score)
}
}
func deleteScore(scores []int, index int) []int {
if index < 0 || index >= len(scores) {
// 如果索引不合法,直接返回原切片
return scores
}
// 使用 append 方法删除索引为 index 的元素
return append(scores[:index], scores[index+1:]...)
}
// 输出:
// 学生 1 的成绩是: 85
// 学生 2 的成绩是: 92
// 学生 3 的成绩是: 90
// 学生 4 的成绩是: 88
在上述示例中,定义了一个名为deleteScore的函数,它接受一个切片和要删除的元素索引。在函数内部,创建了一个新的切片,长度比原切片少 1,并将原切片的一部分复制到新切片中,跳过要删除的元素。最后,将新切片复制回原切片中,实现了元素的删除。在main函数中,调用deleteScore函数删除索引为 2 的元素,并输出删除后的切片元素。
2.2 切片截取
Go的切片截取采用左闭右开的原则,闭[ 代表包含这个元素,开) 表示不包含这个元素
arr[start:end],获取的是[start,end)之间的元素
arr[:end],获取的是[0,end)之间的元素
arr[start:],获取的是[start,len(arr))之间的元素
切片截取是一种常见的操作,它允许我们从原始切片中获取子切片。通过指定起始索引和结束索引(不包括结束索引),可以获取指定范围内的元素。
以下是一个示例,展示了如何进行切片截取:
package main
import "fmt"
// 定义一个切片
var scores = []int{90, 70, 50, 80, 60}
func main() {
// 截取子切片
subScores := scores[1:3]
fmt.Println("子切片:", subScores) // 子切片: [70 50]
// 截取子切片1
subScores1 := scores[:3]
fmt.Println("子切片1:", subScores1) // 子切片2: [90 70 50]
// 截取子切片2
subScores2 := scores[2:]
fmt.Println("子切片2:", subScores2) // 子切片1: [50 80 60]
}
在上面的示例中,我们从原始切片scores中截取了子切片subScores,其范围是从索引 1 到索引 3(不包括索引 3)。输出结果将显示子切片中的元素。
2.3 切片排序
切片的排序可以通过标准库中的sort函数来实现。sort函数可以对切片进行升序或降序排序。
以下是一个示例,展示了如何对切片进行排序:
package main
import (
"fmt"
"sort"
)
// 定义一个切片
var scores = []int{50, 80, 30, 60, 90}
func main() {
// 对切片进行排序
sort.Ints(scores)
// 输出排序后的切片
for i, score := range scores {
fmt.Printf("学生 %d 的成绩是: %d\n", i+1, score)
}
}
// 学生 1 的成绩是: 30
// 学生 2 的成绩是: 50
// 学生 3 的成绩是: 60
// 学生 4 的成绩是: 80
// 学生 5 的成绩是: 90
2.4 切片的合并
切片的合并可以通过将多个切片连接在一起来实现。可以使用...操作符将一个切片展开为多个元素,然后将它们添加到另一个切片中。
以下是一个示例,展示了如何合并两个切片:
package main
import "fmt"
// 定义两个切片
var slice1 = []int{10, 20, 30}
var slice2 = []int{40, 50, 60}
func main() {
// 合并两个切片
slice3 := append(slice1, slice2...)
fmt.Println("合并后的切片:", slice3) // [10 20 30 40 50 60]
}
在上面的示例中,使用append函数将slice1和slice2合并到slice3中。通过...操作符将slice2展开为多个元素,然后将它们添加到slice1的后面。最后,输出合并后的切片slice3的内容。
2.5 判断某个元素是否在切片中
要判断某个元素是否在切片中,可以通过遍历切片的方式来实现。以下是一个示例代码:
package main
import (
"fmt"
)
// contains 检查切片中是否包含指定的元素
func contains[T comparable](slice []T, element T) bool {
for _, v := range slice {
if v == element {
return true
}
}
return false
}
func main() {
intSlice := []int{1, 2, 3, 4, 5}
stringSlice := []string{"apple", "banana", "cherry"}
// 检查整数切片
intElement := 3
if contains(intSlice, intElement) {
fmt.Printf("整数切片包含元素 %d\n", intElement)
} else {
fmt.Printf("整数切片不包含元素 %d\n", intElement)
}
// 检查字符串切片
stringElement := "banana"
if contains(stringSlice, stringElement) {
fmt.Printf("字符串切片包含元素 %s\n", stringElement)
} else {
fmt.Printf("字符串切片不包含元素 %s\n", stringElement)
}
}
在上述代码中,定义了一个通用的contains函数,它可以处理任何可比较类型的切片。通过遍历切片中的每个元素,与给定的元素进行比较,如果找到了匹配项就返回true,遍历结束都未找到则返回false。
在main函数中,分别对整数切片和字符串切片进行了元素是否存在的判断,并根据结果输出相应的信息。这种通过自定义函数来检测元素是否在切片中的方法,提高了代码的复用性和可读性。
2.6 切片去重
实现切片去重可以通过多种方式,下面是一种常见的方法:
package main
import "fmt"
// unique 对切片进行去重操作
func unique(slice []int) []int {
result := []int{}
seen := make(map[int]bool)
for _, num := range slice {
if!seen[num] {
result = append(result, num)
seen[num] = true
}
}
return result
}
func main() {
slice := []int{1, 2, 2, 3, 3, 3, 4, 4, 4, 4}
uniqueSlice := unique(slice)
fmt.Println("去重后的切片:", uniqueSlice)
}
在上述代码中,unique函数使用一个map来记录已经出现过的元素。遍历输入的切片时,如果某个元素还未在map中出现,就将其添加到结果切片和map中。这种方式能够有效地去除切片中的重复元素,并保持原始元素的顺序。
在main函数中,给出了一个包含重复元素的整数切片,并调用unique函数对其进行去重操作,最后打印出去重后的切片。这种去重方法在实际编程中经常使用,对于处理需要消除重复元素的数据非常有帮助。
2.7 切片扩容
切片扩容:重新分配一段连续内存,而后把原有的数据拷贝过去
在Go语言中,当切片的容量<1024时,切片会翻倍,>1024时,切片每次会增加约1/4
坑点:
package main
import "fmt"
func main() {
// 原始切片
s1 := make([]int, 0, 2)
s1 = append(s1, 1, 2) // 此时s1已满 (len=2, cap=2)
// 让s2成为s1的一个“视图”
s2 := s1
fmt.Printf("初始状态: s1: %v, ptr: %p | s2: %v, ptr: %p\n", s1, s1, s2, s2)
// 对s1进行append,触发扩容
s1 = append(s1, 3)
fmt.Printf("扩容后: s1: %v, ptr: %p | s2: %v, ptr: %p\n", s1, s1, s2, s2)
// 修改s1的第一个元素
s1[0] = 100
fmt.Printf("修改s1后: s1: %v | s2: %v\n", s1, s2)
// 输出结果:
// 初始状态: s1: [1 2], ptr: 0xc000018050 | s2: [1 2], ptr: 0xc000018050
// 扩容后: s1: [1 2 3], ptr: 0xc00001c080 | s2: [1 2], ptr: 0xc000018050
// 修改s1后: s1: [100 2 3] | s2: [1 2]
}
s1和s2最初指向同一块底层数组。对
s1进行append导致扩容,系统为s1重新分配了一块新内存,并将[1, 2, 3]拷贝过去。此时,s1指向了新地址。s2仍然指向旧的底层数组,其内容仍然是[1, 2]。之后对
s1的修改,完全不会影响到s2。
三、Map
Map 是 Go 语言中的一种无序键值对数据结构。它用于存储键值对,可以通过键来快速访问对应的值。Map 中的键可以是任何类型,而值可以是任何类型。
Go 语言中的 map 是引用类型,必须初始化才能使用
初始化:dd := make(map[string]string)
以下是一个创建和使用 Map 的示例:
package main
import "fmt"
func main() {
// 创建一个空的 Map
studentGrades := make(map[string]int)
// 向 Map 中添加键值对
studentGrades["Alice"] = 85
studentGrades["Bob"] = 90
studentGrades["Charlie"] = 75
// 通过键获取对应的值
gradeForAlice := studentGrades["Alice"]
fmt.Println("Alice 的成绩是:", gradeForAlice) // Alice 的成绩是: 85
// 检查键是否存在于 Map 中
exists := studentGrades["David"]
fmt.Println("David 是否有成绩:", exists) // David 是否有成绩: 0
}
在上面的示例中,我们创建了一个名为studentGrades的空 Map。然后,使用键值对的方式向 Map 中添加数据。通过键"Alice"可以获取到对应的值 85。最后,我们检查键"David"是否存在于 Map 中,并输出结果。
3.1 判断某个键是否存在
可以通过访问特定键对应的值来判断该键是否存在于 Map 中。如果值为nil,则表示键不存在;如果值不为nil,则表示键存在。
以下是一个示例:
package main
import "fmt"
func main() {
userInfo := map[string]string{"username": "zhangsan", "password": "123456"}
v, ok := userInfo["username"]
if ok {
fmt.Println(v) // zhangsan
} else {
fmt.Println("map中没有此元素")
}
}
3.2 Map的删除delete()函数
要从 Map 中删除一个键值对,可以使用 delete 函数。delete 函数接受一个 Map 和一个键作为参数,并删除与该键相关联的值。
以下是一个示例:
package main
import "fmt"
func main() {
userInfo := map[string]string{"username": "root", "password": "123456"}
delete(userInfo, "password") //将 password从 map 中删除
fmt.Println(userInfo) // map[username:root]
}
Map 是 Go 语言中非常强大和实用的数据结构,它能够高效地存储和操作键值对数据。通过灵活运用判断键是否存在、删除键值对等操作,我们可以根据不同的业务需求来对 Map 进行定制化的处理。
比如在一个用户管理系统中,我们可以使用 Map 来存储用户的各种信息。当需要更新或删除某个用户的特定信息时,上述的方法就派上了用场。
假设我们有一个电商系统,商品的库存信息也可以用 Map 来存储。键可以是商品的 ID,值则是对应的库存数量。当商品被售出或者补充库存时,就可以方便地对 Map 进行相应的修改和操作。
四、make函数
make函数用于创建切片、映射和通道。它可以指定这些数据结构的初始容量。例如,我们可以使用make函数创建一个具有特定容量的切片。
以下是一个使用make函数创建切片的示例:
package main
import "fmt"
func main() {
// 使用 make 函数创建一个容量为 10 的整数切片
scores := make([]int, 10)
// 填充切片
for i := 0; i < 10; i++ {
scores[i] = i * 5
}
// 输出切片元素
for i, score := range scores {
fmt.Printf("元素 %d: %d\n", i+1, score)
}
}