这篇主要学习下golang中的数组及slice(切片)及常规操作, 主要是slice, 但是并不会涉及slice的底层原理, 这个范围比较大, 有必要单独拎出来.
数组(array)
定义
数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度, 数组的大小是类型的一部分。因此[5]int和[25]int是不同的类型
数组的大小必须是常量表达式, 也就是说长度需要在编译阶段能够确认.
1 | // 数组有如下几种声明方式: |
简单来说就是, 在定义数组时需要为数组指定长度, 或者使用[…], 如果未指定的即为slice
访问
1 | aRray := [...]int{1, 3, 5, 7} |
比较
数组的大小是类型的一部分。因此[5]int和[25]int是不同的类型,只有在当数据的长度及类型完全一样时,该数据组才能比较
1 | aRray := [...]int{1, 3, 5, 7} |
只有在当数组的长度及类型及元素值完全一样时,该数组才相等, 注意,相等并不相同.
遍历
1 | aRray := [...]int{1, 3, 5, 7} |
slice
slice表示一个拥有相同类型元素的可变长度的序列,slice是一种轻量的数据结构, 可以用来访问数组的部分或者全部元素,而这个元素称为slice的底层数组, 这里先只学习slice的常用操作,slice 底层结构原理会单独记录.
现在可以简单这样理解: slice是底层数组的一层view.
**slice是由三部分组成: 第1个参数是指向底层数组的指针(ptr),这个指针指向真正存储数据的块, 第2个参数是长度(len), 第三个参数是容量(cap)
定义
1 | // 通过字面量创建 |
访问
1 | // 下标是从0开始 ,按下标访问 |
遍历
1 | // slice的遍历方法写数组是一样的 |
方法
1 | eSlice := [10]int{1, 2, 3, 4, 5} // [1 2 3 4 5 0 0 0 0 0] |
Reslice
1 | // 定义一个数组 |
gSlice := fSlice[1:5]
为何会输出[4 5 0 0 ]
呢, gSlice的值为[3 4 ], 压根就没有[1: 5],那它为何没有提示越界访问呢?这个其实就是对slice是底层数组的一层view的说明
slice是支持向后扩展的, eSlice其实就是fSlice跟gSlice的底层数组, 只要不超过底层数组的cap,就可以反应在slice上,这也是fSlice[1:5]不报错的原因
fSlice[1:10]是由于gSlice本身有了2个元素, 整个只有8个元素,因此越界.
append
向slice追加元素的时候需要注意存在修改底层数组及扩容的问题.
1 | // 修改底层数组 |
delete/insert/replace
1 | // 删除hSlice第二个元素5 |
copy
内置函数 copy() 可以将一个数组切片复制到另一个数组切片中,如果加入的两个数组切片不一样大,就会按照其中较小的那个数组切片的元素个数进行复制
1 | // 常规的赋值 |
上面所有的例子都跟slice的底层数据结构有很大的关系, 后续会对slice底层原理写一个详文.