概念
切片 (slice) 是对数组一个连续片段的引用,, 所以切片是一个引用类型(更类似于 C/C++ 中的数组, Python 中的 list ). 因为切片是引用, 不需要使用额外的内存存储并且比数组更有效率, 所以在 Go 中 切片比数组更常用.
构成
一个 slice 由三个部分构成: 指针, 长度和容量:
指针: 指向第一个 slice 元素对应的底层数组元素的地址(注意, slice 的第一个元素并不一定就是数组的第一个元素)
长度对应 slice 中元素的数目, 不能超过容量
容量一般是从 slice 的开始位置到底层数组的结尾位置, 内置的 len 和 cap 函数分别返回 slice 的长度和容量.
创建
数组切片
Slice 本身没有数据, 是对底层数组的 view. 多个 slice 之间可以共享底层的数据, 并且引用的数组部分区间可能重叠, 即一个切片和相关数组的其他切片是共享存储的. 相反, 不同的数组总是代表不同的存储(数组实际上是切片的构建块).
- arr := [...]int{
- 0, 1, 2, 3, 4, 5, 6, 7
- } // [0 1 2 3 4 5 6 7]
- s := arr[2:6] // [2 3 4 5]
- // 共享存储
- s[0] = 10
- fmt.Println(arr) // [0 1 10 3 4 5 6 7]
- fmt.Println((s)) // [10 3 4 5]
数组和 slice 之间有着紧密的联系, 和数组不同的是, 切片的长度可以在运行时修改, 最小为 0 最大为相关数组的长度, 切片是一个 长度可变的数组.
声明赋值
切片与数组的类型字面量的唯一不同是不包含代表其长度的信息. 因此, 不同长度的切片值是有可能属于同一个类型的, 不同长度的数组值必定属于不同类型.
s := []int{1, 2, 3}
使用 append
由于值传递的关系, 必须接收 append 的返回值:
- s = append(s, val)
- s = append(s, val1,val2, val3)
- s = append(s, slice...)
- var s []int
- for i :=0; i<10; i++ {
- s = append(s, i)
- }
- fmt.Println(s)
使用 make
cap 是可选参数: make([]type, len, cap)
- s1 := make([]int, 16)
- s2 := make([]int, 10, 32)
- // 数组的容量是其长度
- arr := [...]int{
- 0, 1, 2, 3, 4, 5, 6, 7
- }
- fmt.Println(cap(arr)) // 8
- // 切片的容量
- arr := [...]int{
- 0, 1, 2, 3, 4, 5, 6, 7
- }
- s1 := arr[2:6] // [2 3 4 5]
- s2 := s1[3:5] // [5 6], 注意, 扩展了
- fmt.Println(cap(s1)) // 6
- fmt.Println(cap(s2)) // 3
- arr := [...]int{
- 0, 1, 2, 3, 4, 5, 6, 7
- }
- s1 := arr[2:6]
- s2 := s1[3:5]
- s3 := append(s2, 10)
- s4 := append(s3, 11)
- s5 := append(s4, 12)
- fmt.Println(s1) // [2 3 4 5]
- fmt.Println(s2) // [5 6], 注意, 扩展了 s1
- fmt.Println(s3) // [5 6 10]
- fmt.Println(s4) // [5 6 10 11]
- fmt.Println(s5) // [5 6 10 11 12]
- fmt.Println(arr) // [0 1 2 3 4 5 6 10]
- var s []int
- for i :=0; i<10; i++ {
- s = append(s, i)
- fmt.Println(len(s), cap(s))
- }
- fmt.Println(s)
- // 1 1
- // 2 2
- // 3 4
- // 4 4
- // 5 8
- // 6 8
- // 7 8
- // 8 8
- // 9 16
- // 10 16
- // [0 1 2 3 4 5 6 7 8 9]
- arr := [...]int{
- 0, 1, 2, 3, 4, 5
- }
- s := arr[:] // [0 1 2 3 4 5]
- s = append(s[:3], s[4:]...)
- fmt.Println(s) // [0 1 2 4 5]
- s1 := []int{
- 1, 2
- }
- s2 := []int{
- 4, 5, 6
- }
- copy(s1, s2)
- fmt.Println(s1) // [4 5]
- s1 := []int{
- 1, 1, 1, 1
- }
- s2 := []int{
- 4, 5, 6
- }
- copy(s1, s2)
- fmt.Println(s1) // [4 5 6 1]
- func equal(x, y []string) bool {
- if len(x) != len(y) {
- return false
- }
- for i := range x {
- if x[i] != y[i] {
- return false
- }
- }
- return true
- }
- var s1 []int
- fmt.Println(len(s1), s1 == nil) // 0 true
- s2 := []int{
- }
- fmt.Println(len(s2), s2 == nil) // 0 false
- s3 := []int(nil)
- fmt.Println(len(s3), s3 == nil) // 0 true
- package main
- import "fmt"
- func sum(a []int) int {
- s := 0
- for i := range a {
- s += i
- }
- return s
- }
- func main() {
- arr := [...]int{0, 1, 2, 3, 4, 5}
- fmt.Println(sum(arr[:])) // 15
- var s1 []int
- fmt.Println(s1 == nil, sum(s1)) // true 0
- s2 := []int{}
- fmt.Println(s2 == nil, sum(s2)) // false 0
- }
- package main
- import "fmt"
- func reverse(s []int) {
- // for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
- // s[i], s[j] = s[j], s[i]
- // }
- for index, i := range s {
- s[index], s[len(s) - i - 1] = s[len(s) - i - 1], s[index]
- }
- }
- func main() {
- arr := [...]int{0, 1, 2, 3, 4, 5}
- reverse(arr[:])
- fmt.Println(arr)
- var s1 []int
- reverse(s1)
- fmt.Println(s1)
- s2 := []int{}
- reverse(s2)
- fmt.Println(s2)
- }
- package main
- import (
- "fmt"
- )
- func nonempty(strings []string) []string {
- i := 0
- for _, s := range strings {
- if s != "" {
- strings[i] = s
- i++
- }
- }
- return strings[:i]
- }
- func main() {
- data := []string{"one", "","three"}
- fmt.Printf("%q\n", nonempty(data)) // ["one" "three"]
- fmt.Printf("%q\n", data) // ["one" "three" "three"], 改变原数组
- }
- func nonempty2(strings []string) []string {
- out := strings[:0] // 注意, 重用原 slice 的关键
- for _, s := range strings {
- if s != "" {
- out = append(out, s)
- }
- }
- return out
- }
- func remove(slice []int, i int) []int {
- copy(slice[i:], slice[i+1:])
- return slice[:len(slice)-1]
- // 或者
- // return append(slice[:i], slice[i+1:]...)
- }
- func appendInt(x []int, y int) []int {
- var z []int
- zlen := len(x) + 1
- if zlen <= cap(x) {
- // There is room to grow. Extend the slice.
- z = x[:zlen]
- } else {
- // There is insufficient space. Allocate a new array.
- // Grow by doubling, for amortized linear complexity.
- zcap := zlen
- if zcap < 2*len(x) {
- zcap = 2 * len(x)
- }
- z = make([]int, zlen, zcap)
- copy(z, x) // a built-in function; see text
- }
- z[len(x)] = y
- return z
- }
- type IntSlice struct {
- ptr *int
- len, cap int
- }
- var x []int
- x = append(x, 1)
- x = append(x, 2, 3)
- x = append(x, 4, 5, 6)
- x = append(x, x...) // append the slice x
- func appendInt(x []int, y ...int) []int {
- var z []int
- zlen := len(x) + len(y)
- // ...expand z to at least zlen...
- copy(z[len(x):], y)
- return z
- }
来源: https://juejin.im/post/5c7c771ff265da2db912888d