数组
定义:由若干相同类型的元素组成的序列
数组的长度是固定的,声明后无法改变
数组的长度是数组类型的一部分,eg:元素类型相同但是长度不同的两个数组是不同类型的
需要严格控制程序所使用内存时,数组十分有用,因为其长度固定,避免了内存二次分配操作
示例
package main
import "fmt"
func main() {
// 定义长度为 5 的数组
var arr1 [5]int
for i := 0; i < 5; i++ {
arr1[i] = i
}
printHelper("arr1", arr1)
// 以下赋值会报类型不匹配错误,因为数组长度是数组类型的一部分
// arr1 = [3]int{1, 2, 3}
arr1 = [5]int{2, 3, 4, 5, 6} // 长度和元素类型都相同,可以正确赋值
// 简写模式,在定义的同时给出了赋值
arr2 := [5]int{0, 1, 2, 3, 4}
printHelper("arr2", arr2)
// 数组元素类型相同并且数组长度相等的情况下,数组可以进行比较
fmt.Println(arr1 == arr2)
// 也可以不显式定义数组长度,由编译器完成长度计算
var arr3 = [...]int{0, 1, 2, 3, 4}
printHelper("arr3", arr3)
// 定义前四个元素为默认值 0,最后一个元素为 -1
var arr4 = [...]int{4: -1}
printHelper("arr4", arr4)
// 多维数组
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("twoD: ", twoD)
}
func printHelper(name string, arr [5]int) {
for i := 0; i < 5; i++ {
fmt.Printf("%v[%v]: %v\n", name, i, arr[i])
}
// len 获取长度
fmt.Printf("len of %v: %v\n", name, len(arr))
// cap 也可以用来获取数组长度
fmt.Printf("cap of %v: %v\n", name, cap(arr))
fmt.Println()
}
在Go语言中,声明和初始化可以一起完成,因此这行代码是有效的,并且符合Go语言的语法规则。
总结起来:
变量的声明可以同时包括初始化操作。
变量的声明和初始化可以在包级别(全局变量)或函数内部进行。
赋值操作是指将一个已经声明的变量更新为新的值,在Go语言中,这种操作必须在函数体内部执行
切片
切片组成要素:
指针:指向底层数组
长度:切片中元素的长度,不能大于容量
容量:指针所指向的底层数组的总容量
常见初始化方式
使用
make
初始化
slice := make([]int, 5) // 初始化长度和容量都为 5 的切片
slice := make([]int, 5, 10) // 初始化长度为 5, 容量为 10 的切片
使用简短定义
slice := []int{1, 2, 3, 4, 5}
使用数组来初始化切片
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[0:3] // 左闭右开区间,最终切片为 [1,2,3]
使用切片来初始化切片
sliceA := []int{1, 2, 3, 4, 5}
sliceB := sliceA[0:3] // 左闭右开区间,sliceB 最终为 [1,2,3]
长度和容量
package main
import (
"fmt"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Println("len: ", len(slice))
fmt.Println("cap: ", cap(slice))
//改变切片长度
slice = append(slice, 6)
fmt.Println("after append operation: ")
fmt.Println("len: ", len(slice))
fmt.Println("cap: ", cap(slice)) //注意,底层数组容量不够时,会重新分配数组空间,通常为两倍
}
以上代码,预期输出如下:
len: 5
cap: 5
after append operation:
len: 6
cap: 12
注意点
多个切片共享一个底层数组的情况
对底层数组的修改,将影响上层多个切片的值
package main
import (
"fmt"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[0:3]
fmt.Println("before modifying underlying array:")
fmt.Println("slice: ", slice)
fmt.Println("newSlice: ", newSlice)
fmt.Println()
newSlice[0] = 6
fmt.Println("after modifying underlying array:")
fmt.Println("slice: ", slice)
fmt.Println("newSlice: ", newSlice)
}
以上代码预期输出如下:
before modify underlying array:
slice: [1 2 3 4 5]
newSlice: [1 2 3]
after modify underlying array:
slice: [6 2 3 4 5]
newSlice: [6 2 3]
使用
copy
方法可以避免共享同一个底层数组
示例代码如下:
package main
import (
"fmt"
)
func main() {
slice := []int{1, 2, 3, 4, 5}
newSlice := make([]int, len(slice))
copy(newSlice, slice)
fmt.Println("before modifying underlying array:")
fmt.Println("slice: ", slice)
fmt.Println("newSlice: ", newSlice)
fmt.Println()
newSlice[0] = 6
fmt.Println("after modifying underlying array:")
fmt.Println("slice: ", slice)
fmt.Println("newSlice: ", newSlice)
}
以上代码预期输出如下:
before modifying underlying array:
slice: [1 2 3 4 5]
newSlice: [1 2 3 4 5]
after modifying underlying array:
slice: [1 2 3 4 5]
newSlice: [6 2 3 4 5]
小练习
如何使用 copy
函数进行切片部分拷贝?
// 假设切片 slice 如下:
slice := []int{1, 2, 3, 4, 5}
// 如何使用 copy 创建切片 newSlice, 该切片值为 [2, 3, 4]
newSlice = copy(?,?)
// 假设切片 slice 如下:
sliceD := []int{1, 2, 3, 4, 5}
// 如何使用 copy 创建切片 newSlice, 该切片值为 [2, 3, 4]
newSliceE := make([]int, 3)
copy(newSliceE, sliceD[1:4])
fmt.Println("newSliceE", newSliceE)