数组是 同一类型元素 的集合,Go 语言中不允许混合不同类型的元素。
一个数组的表示形式为 [n]T
。n 表示数组中元素的数量,T 代表每个元素的类型。如: var arr [3]int
。
数组简略声明:arr := [3]int{12, 78, 50}
,在简略声明中,可对部分元素赋值:arr := [3]int{12}
,剩下的元素自动赋值为 0 。
可以忽略声明数组的长度,并用 ...
代替,让编译器为你自动计算长度:arr := [...]int{12, 21}
。
数组是值类型,不是引用类型 :这意味着当数组赋值给一个新变量时,该变量会得到一个原始数组的副本。 如果对新变量进行修改,不会影响原始数组。注:对切片的修改会影响原始数组。
1 | func changeLocal(num [5]int) { |
数组的长度:len(arr)
。
数组的迭代一:for 循环。
1 | for i := 0; i < len(arr); i++ { |
range
方法来遍历数组。range
返回索引和该索引处的值。1 | for i, v := range arr { |
1 | arr := [3][2]string{ // 简略声明 |
切片是 由数组建立 的一种方便、灵活且功能强大的包装(Wrapper)。切片本身不拥有任何数据 ,它只是对现有数组的 引用。
创建一个切片 A :带有 T
类型元素的切片由 []T
表示。语法:a[start:end]
创建一个从 a 数组索引 start 开始到 end - 1 结束的切片。
1 | arr := [5]int{76, 77, 78, 79, 80} |
[]
内无内容。1 | c := []int{6, 7, 8} // creates and array and returns a slice reference |
对切片的修改会影响原始数组。当多个切片共用相同的底层数组时,每个切片所做的更改将反映在原始数组中。
切片的长度和容量:切片的长度是切片中的元素数。切片的容量是从创建切片索引开始(到数组末尾)的底层数组中的元素数。
1 | func main() { |
slicename[:cap(slicename)]
。1 | func main() { |
使用 make
创建一个切片:func make ([]T, len, cap)
通过传递类型、长度和容量来创建切片。其中,容量是可选参数,默认值为切片长度。make
函数创建一个数组,并返回引用该数组的切片。如 arrslice := make([]float64, 5, 5)
。
切片是动态的,可以使用 func append(slice []T, x ...T) []T
将新元素追加到切片上。其中 x ...T
表示该函数接收 T
类型的参数 x
的个数是可变的,如:arrslice = append(arrslice, 5.6, 7.3)
。
append
函数会返回一个 新的切片,其中包含了原始切片和追加的元素:
- 如果原始切片的容量足够,
append
函数会在原始切片的基础上进行追加;- 如果原始切片的容量不够,
append
函数会创建一个新的底层数组,并将原始切片中的元素和追加的元素复制到新的底层数组中。因此,append 函数 返回的切片可能指向一个新的底层数组,而不是原始切片所指向的底层数组。
数组是固定的,但 切片具有动态长度 :切片是由一个指向数组的指针、长度和容量组成的数据结构。当我们向切片中追加元素时,如果切片的长度小于容量,新元素会直接添加到切片的末尾,切片的长度会增加。但是,如果追加元素后切片的长度超过了容量,Go 语言会创建一个新的更大的底层数组,将原来的元素复制到新的数组中,并将新元素添加到新数组的末尾。然后,切片会指向这个新数组( 相比于旧切片,引用类型的地址改变了),并且容量会成为原来的两倍(并不是每次执行 append
时容量都会变成旧切片的两倍,只有当长度超过容量时,才会扩充一倍容量)。这样,切片就具有了动态长度的特性。
切片类型的零值为 nil
:一个 nil
切片的长度和容量为 0,可以使用 append
函数将值追加到 nil
切片。
1 | var names []string // zero value of a slice is nil |
...
可将一个切片添加到另一个切片中:append(slice1, slice2...)
。
切片的函数传递:切片在内部可由一个结构体类型表示,即:
1 | type slice struct { |
切片本身包含了长度、容量和指向底层数组首个元素的指针。当切片作为参数传递给函数时,虽然是通过值传递,但是切片内部的指针变量(这里的byte
)仍然指向相同的底层数组。因此,当函数内部修改底层数组的值时,这些修改在函数外部是可见的。
然而,如果函数内部修改了切片的长度或容量,将会创建一个新的切片,而不会影响原始切片。这是因为切片的长度和容量是切片结构体的字段,而非底层数组的属性。因此,修改切片的长度或容量会创建一个新的切片结构体,其中的指针变量仍然指向原始的底层数组,但是新的切片具有不同的长度和容量。
因此,可以说当切片传递给函数时,函数内部对底层数组的修改,在函数外部是可见的,但是对切片的长度和容量的修改是不可见的。
1 | func modifySlice(s []int) { |
1 | pls := [][]string { |
copy
函数 func copy(dst, src[]T) int
来生成一个切片的副本,这样就可以使用新的切片,原始数组也可以被垃圾回收。注:返回的 int 类型的值为 dst 的长度。1 | func countries() []string { |
学习链接:https://studygolang.com/subject/2,感谢如此优秀的教程!