【笔记】Go语言的切片

前言

Go语言的切片(slice)相当于动态数组(伸缩数组),切片存放在内存的堆区,属于引用类型数据类型

通过切数组得到切片

  • 切片是对数组的一个引用
  • 每一个切片只存放三个数据,分别是:内存地址、切片长度、切片容量
    • 数组起始切的内存地址:指向的数组的起始切的位置的内存地址
    • 切片长度:切的长度
    • 切片容量:指向的数组的起始切的位置直到该数组结尾的长度
1
2
var 数组变量 [3]string = [3]string{1, 2, 3}
var 切片变量 []string = 数组变量[1:2]

当前切片的数组起始切的内存地址为源数组变量的下标为1的内存地址
当前切片的长度为1
当前切片的容量为2

声明切片

  • 没有指定切片长度时,切片容量和切片长度默认都为0,其中没有数据
1
var 切片名 []数据类型

声明时指定切片长度

  • 指定了切片长度时,切片长度为指定值,切片的容量为大于等于指定值的最小偶数,其中数据都为默认值
1
切片名 := make([]数据类型, 切片长度)

定义切片

1
var 切片名 []数据类型 = []数据类型{数据, 数据, ...}
  • 实际上是定义了一个数组,然后向数组中填充内容,然后再进行一次切片得到切片
    • 该切片的数组起始切的内存地址为源内存首元素地址
    • 该切片的长度和容量相同,都为源数组长度
1
2
var 数组变量 [3]string = [3]string{1, 2, 3}
var 切片变量 []string = 数组变量[:]

获取切片指定下标元素的值

1
切片名[下标]

修改切片指定下标元素的值

1
切片名[下标] = 数据

获取切片长度

1
len(切片名)

获取切片容量

  • 容量大于等于长度
  • 自动扩容时
    • 如果没有超过1024字节,每次扩展为上次容量的2倍
    • 如果超过了1024字节,每次扩展为上次容量的1.25倍
1
cap(切片名)

追加切片数据

  • 在切片末尾追加数据
    • 如果追加前容量大于长度,则容量不会改变
    • 如果追加前容量等于长度,则容量将自动扩容
      • 扩容时将以当前的容量的2倍扩容,并将原数组数据进行拷贝
1
2
3
切片名 = append(切片名, 数据)
切片名 = append(切片名, 数据, 数据, ...)
切片名 = append(切片名, 其他切片...)

开头追加元素

1
切片名 = append([]数据类型{值}, 切片名...)

中间插入元素

1
切片名 = append(切片名[:索引], append([]数据类型{值}, 切片名[索引:]...)...)

删除元素

1
切片名 = append(切片名[:索引], 切片名[索引+1:]...)

遍历切片

1
2
3
4
for i := 0; i < len(切片); i++ {
fmt.Println("切片下标: ", i)
fmt.Println("切片元素: ", 数组名[i])
}
1
2
3
4
for i, v := range 数组名 {
fmt.Println("切片下标: ", i)
fmt.Println("切片元素: ", v)
}

切片的截取

指定区间

  • 包含开始不包含结尾
1
新的切片名 = 旧的切片名[开始位置下标:结束位置下标]

截取到末尾

  • 包含开始位置
1
新的切片名 = 旧的切片名[开始位置下标:]

从头开始截取

  • 不包含结束位置
1
新的切片名 = 旧的切片名[:结束位置下标]

指定截取后的切片容量

  • 新的切片的容量应当大于等于截取后的长度
  • 新的切片的容量应当小于旧的切片的容量
1
新的切片名 = 旧的切片名[开始位置下标:结束位置下标:新的切片的容量]

改变数据

  • 截取后的切片仍然属于旧的切片的一部分,所以当修改新的切片的数据时,旧的切片中数据也会发生改变
1
2
新的切片名[下标] = 新数据
fmt.Println(旧的切片名[下标])

切片数据的拷贝

  • 将旧切片中的数据拷贝到新切片中
  • 切片数据拷贝时,要求新的切片的容量大于等于旧的切片的长度
  • 拷贝操作得到的新切片与旧切片是两个单独的切片,数据不会相互影响
1
2
3
var 旧的切片名 []数据类型 = []数据类型{}
新的切片名 = make([]数据类型, len(旧的切片名))
copy(新的切片, 旧的切片)

只拷贝部分数据

  • 切片数据拷贝时,要求新的切片的容量大于等于产生的新的切片的长度
1
copy(新的切片, 旧的切片[开始位置:结束位置])
1
copy(新的切片, 旧的切片[开始位置:])
1
copy(新的切片, 旧的切片[:结束位置])

切片作为函数参数

  • 切片作为函数参数传递时是地址传递,形参可以改变实参的值
    • 如果是修改切片内数据的操作,实参内的数据会跟随形参发生改变
    • 如果是追加切片数据的操作,实参内的数据有可能不发生改变,因为在追加操作时,内存地址可能发生改变,不变实参指向的内存地址不变,所以实参内的数据可能不会发生改变
1
2
3
4
5
func 函数名(切片名 []数据类型) {}

func main() {
函数名(切片名)
}

切片作为返回值

1
2
3
4
5
6
7
func 函数名(切片名 []数据类型) []数据类型{
return 切片名
}

func main() {
切片名 := 函数名(切片名)
}

完成

参考文献

哔哩哔哩——喔咔咔耶耶
哔哩哔哩——Python路飞