数组
Go 数组的大小是固定的,其长度是其类型的一部分([4]int并且[5]int是不同的、不兼容的类型)
var a [10]intb := [2]string{"Penn", "Teller"}
b := [...]string{"Penn", "Teller"}
package mainimport "fmt"func main() {var a [2]stringa[0] = "Hello"a[1] = "World"fmt.Println(a[0], a[1])fmt.Println(a)primes := [6]int{2, 3, 5, 7, 11, 13}fmt.Println(primes)
}
Go的数组表示值,数组变量表示整个数组;它不是指向第一个数组元素的指针(在 C 中是这种情况)。这意味着当您分配或传递数组值时,您将复制其内容。(为了避免复制,您可以将指针传递给数组,但那是指向数组的指针,而不是数组。)
package mainimport "fmt"// 函数接收数组指针作为参数。
// 如果不用指针,接收到的将是arr的副本,在函数内部修改不会影响到原数组。
func modifyArrayPointer(arr *[5]int) {arr[0] = 100 // 修改数组的第一个元素fmt.Println("Inside modifyArrayPointer:", *arr) // 打印修改后的数组
}func main() {arr := [5]int{1, 2, 3, 4, 5}fmt.Println("修改前:", arr)modifyArrayPointer(&arr) // 传递数组的指针fmt.Println("修改后:", arr) // 原数组被改变
}
切片
切片类型是基于Go数组类型之上的抽象,提供了更强大的功能和便利性。
数组大小固定,而切片则为数组元素提供了动态大小、灵活的视角。在实践中,切片比数组更常用。
切片是数组段的描述符。由指向数组的指针、段的长度及其容量(段的最大长度)组成。
[]T 表示一个元素类型为T的切片。
切片通过两个下标界定,左闭右开
a[low : high]
如下表示,包含下标从1到3的元素
a[1:4]
package mainimport "fmt"func main() {primes := [6]int{2, 3, 5, 7, 11, 13}var s []int = primes[1:4]fmt.Println(s)
}
s := make([]byte, 5) 结构如下
s = s[2:4]
切片类似数组引用
切片就像数组的引用 切片并不存储任何数据,它只是描述了底层数组中的一段。
更改切片的元素会修改其底层数组中对应的元素。
它共享底层数组的切片都会观测到这些修改。
使用字面量或make创建切片时,会创建一个新的底层数组。
使用数组或切片重新切片时,不会创建新的数组,而是引用已有的底层数组。
package mainimport "fmt"func main() {names := [4]string{"John","Paul","George","Ringo",}fmt.Println(names)a := names[0:2]b := names[1:3]fmt.Println(a, b)b[0] = "XXX"fmt.Println(a, b)fmt.Println(names)
}
切片字面量(Slice literals)
切片字面量类似于没有长度的数组字面量。
// 这是一个数组字面量:
[3]bool{true, true, false}//下面这样则会创建一个和上面相同的数组,然后再构建一个引用了它的切片:
[]bool{true, true, false}
切片默认行为
在进行切片时,你可以利用它的默认行为来忽略上下界。
切片下界的默认值为 0,上界则是该切片的长度。
对于数组
var a [10]int
来说,以下切片表达式和它是等价的
a[0:10]
a[:10]
a[0:]
a[:]
给定数组创建切片
x := [3]string{"Лайка", "Белка", "Стрелка"}
s := x[:] // a slice referencing the storage of x
切片长度与容量
切片的长度就是它所包含的元素个数。
切片的容量是从它的第一个元素开始数,到其底层数组元素末尾的个数。
- len(s) 切片长度
- cap(s) 切片容量
切片的零值是nil。nil切片的长度和容量为0,且没有底层数组。
使用make创建切片
a := make([]int, 5) // len(a)=5b := make([]int, 0, 5) // len(b)=0, cap(b)=5b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:] // len(b)=4, cap(b)=4
使用append向切片追加元素
func append(s []T, vs ...T) []T
append 的第一个参数 s 是一个元素类型为 T 的切片,其余类型为 T 的值将会追加到该切片的末尾。
append 的结果是一个包含原切片所有元素加上新添加元素的切片。
当 s 的底层数组太小,不足以容纳所有给定的值时,它就会分配一个更大的数组。 返回的切片会指向这个新分配的数组。
package mainimport "fmt"func main() {var s []intprintSlice(s)// 可在空切片上追加s = append(s, 0)printSlice(s)// 这个切片会按需增长s = append(s, 1)printSlice(s)// 可以一次性添加多个元素s = append(s, 2, 3, 4)printSlice(s)
}func printSlice(s []int) {fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
使用range遍历切片
当使用 for 循环遍历切片时,每次迭代都会返回两个值。 第一个值为当前元素的下标,第二个值为该下标所对应元素的一份副本。
package mainimport "fmt"var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}func main() {for i, v := range pow {fmt.Printf("2**%d = %d\n", i, v)}
}
来源
https://tour.go-zh.org/
https://go.dev/tour/welcome/1
https://go.dev/blog/slices-intro