3. 切片
3.1 切片的定义
切片是数组的一个引用,因此切片是引用类型。切片的长度是切片类型的一部分,因此切片的长度是可以改变的。
var s1 []int
s2 := []int{1, 3, 5, 7, 9}
s3 := make([]int, 3, 5)
s4 := append(s3, 11)
s5 := make([]int, 3, 5)
copy(s5, s4)
3.2 切片的遍历
func main() {
s := []int{1, 3, 5}
for i := 0; i < len(s); i++ {
fmt.Println(s[i])
}
for i := range s {
fmt.Println(s[i])
}
for i, v := range s {
fmt.Println(i, v)
}
for _, v := range s {
fmt.Println(v)
}
}
3.3 切片的截取
切片的截取是一个左闭右开的区间。
切片截取后,切片的长度和容量都会发生变化, 长度为截取的长度,容量为原切片的容量减去截取的起始位置。
func main() {
s := []int{1, 3, 5, 7, 9}
fmt.Println(s[2:4])
fmt.Println(s[:4])
fmt.Println(s[2:])
fmt.Println(s[:])
}
3.4 切片的扩展
切片的扩展是指切片的长度超过了切片的容量,此时切片会重新分配内存。
扩容后,切片的指针会发生变化,因此扩容后的切片和原切片不再共享底层数组。
分配内存有两种情况:
- 如果扩容后的容量小于 1024,那么新切片的容量会翻倍,直到新容量大于等于扩容后的容量。
- 如果扩容后的容量大于等于 1024,那么新切片的容量会增加 25%,直到新容量大于等于扩容后的容量。
原因是为了避免内存的频繁分配和释放,因此在扩容时会预留一部分内存,以便下次扩容时可以直接使用。
3.5 切片的删除
func main() {
s1 := []int{1, 3, 5, 7, 9}
// 删除索引为 2 的元素
s2 := append(s1[:2], s1[3:]...)
fmt.Println(s2)
}
3.6 切片的指针
func main() {
s1 := []int{1, 3, 5, 7, 9}
s2 := &s1
s2[0] = 0
fmt.Println(s1)
fmt.Println(s2)
}
4. map
4.1 map 的定义
map 是一种无序的键值对的集合,map 的键是唯一的,但是值可以重复。
var m1 map[string]int
m2 := make(map[string]int)
m3 := map[string]int{"a": 1, "b": 2, "c": 3}
4.2 map 的遍历
map 的遍历是无序的。
如果只遍历 map 的键,可以使用 for range 循环。
如果需要同时遍历 map 的键和值,可以使用 for range 循环。
如果只遍历 map 的值,可以使用 for range 循环,但是需要使用 _ 占位符占位。
顺序遍历 map,需要先将 map 的键放入切片中,然后对切片进行排序,最后遍历切片,根据切片的值取出 map 的值。
func main() {
m := map[string]int{"a": 1, "b": 2, "c": 3}
for k := range m {
fmt.Println(k)
}
for k, v := range m {
fmt.Println(k, v)
}
for _, v := range m {
fmt.Println(v)
}
}
4.3 map 的删除
func main() {
m := map[string]int{"a": 1, "b": 2, "c": 3}
delete(m, "a")
fmt.Println(m)
}
4.4 map 的指针
func main() {
m1 := map[string]int{"a": 1, "b": 2, "c": 3}
m2 := &m1
m2["a"] = 0
fmt.Println(m1)
fmt.Println(m2)
}