美文网首页
Golang笔记(一):数组与切片

Golang笔记(一):数组与切片

作者: MaxHere | 来源:发表于2018-02-03 00:51 被阅读0次

    数组

    • 创建方式:
      以创建 int 类型数组为例
    var array1 [3]int // 元素会被自动初始化为0值 => {0, 0, 0}
    array2 := [3]int{1} // 位提供初始化的元素被初始化为零值 => {1, 0, 0}
    arary3 := [3]int{1, 2: 3} // 指定索引2的元素初始化值为3 => {1, 0, 3}
    array4 := [...]int{1, 2, 3} // 不直接指定长度,编译器会根据元素个数给定长度 => {1, 2, 3}
    array5 := [...]int{1, 2: 3} // 指定索引 2 的元素初始化值为3,会影响该数组长度 => {1, 0, 3}
    
    • 复合型数组:
      复合型数组可以省略类型化标签
    type Student struct {
        name string 
        age    int 
    }
    studentArray := [...]Student {
        {"studentA", 18}, // 省略结构体标签
        {"studentB", 20}
    }
    
    • 多维数组
      注意: 1. 多维数组仅允许第一维使用 ...
      2. 内置函数 len 和 cap 都只返回第一维数组的长度

    • 比较
      如果元素支持 == 比较,那么该数组也支持此操作

    切片

    切片本身是个只读对象,其工作机制累死数组指针的一种包装。可以基于数组或数组指针创建切片,以开始和结束索引位置确定引用的数组片段。不支持反向索引,世纪范围是一个右半开区间。属性 cap 表示切片所引用数组片段的真是长度,len 用于限定可读的写元素数量。另外,数组必须 addressable,否则会引发错误。
    与数组区别:

    1. 切片创建不需要提前声明长度;而数组需要声明,操作数组索引大于该数组长度,会产生越界的异常。
    2. 切片可以通过 make([]int, 3, 5) 方式创建,第一个参数为类型,第二个参数为长度(len),第三个参数为容量(cap)
    3. 切片的长度(len)和 容量(cap)两个属性不一定相等;而数组的两个属性一定相等。切片底层是数组的一部分或者全部, cap 值为从切片引用该底层数组开头部分到该底层数组结尾的长度,而 len 值为该切片引用的底层数组部分的长度。
    4. 切片是引用类型,而数组是值类型。说白了就是切片传递的是引用,只要对任意一个地方修改原切片值也会改变;而数组是值类型,每次传递相当于重新分配内存创建了一个新的数组,各个之间相互独立不影响。
    5. 切片不支持比较操作,即使元素类型支持也不行,仅可以判断您是否是 nil
    • 创建方式:
    sliceA := make([]int, 2, 5)  // len = 2 cap = 5 => {0, 0}
    sliceB := make([]int2, 2]) // len = 2 cap = 5 => {0, 0}
    sliceC := []int{1, 2, 3, 5: 30} // len = 6 cap = 6 => {1, 2, 3, 0, 0, 30}
    

    注意:
    下面两种声明方式,前者只是定义了一个 []int 类型变量,并未执行初始化操作;而后者则用初始化表达式完成了全部创建过程。

    var sliceA []int // sliceA == nil true
    sliceB := []int{} // sliceB == nil false
    
    • 优势
    1. 很显然,切片只是很小的结构体对象,用来代替数组传参可以避免复制开销
    2. make 函数允许在运行期动态制定数组长度,绕开了数组类型必须使用编译期常量的限制。

    然而,并非所有时候都适合使用切片代替数组,因为切片底层数组可能会在堆上分配内存, 而且小数组在栈上拷贝的消耗也未必就比 make 代价大。

    • append
      向切片尾部添加数据(slice[len]),返回新的切片对象(如果超过 cap 限制,则为心切片独享重新分配内存和数组,所以要返回新的切片对象)。向 nil 切片追加数据时,会为其分配底层数组内存。
    slice := make([]int, 0, 5) // {}
    sliceA := append(slice, 10) // {10,}
    sliceB := append(sliceB, 20, 30) // {10, 20, 30}
    sliceC := append(sliceB, 100, 200, 300) // {10, 20, 30, 100, 200, 300} => 超出 cap, 新切片的地址已经变了
    

    注意:

    • 是超出切片 cap 限制,而非超出底层数组长度限制,因为 cap 可小于数组长度。
    • 新分配数组长度是原 cap 的 2 倍,而非原数组的 2 倍(并非总是 2 倍,对于较大的切片,会尝试扩容 1/4,以节约内存)
    • 因为存在重新分配底层数组的缘故,建议预留足够空间,避免多次分配复制的内存开销
    • copy
      在两个切片对象间复制数据,允许指向同一底层数组,允许目标区间重叠。最终所复制长度以较短的切片长度(len)为准。
    slice := []int{1, 2, 3, 4, 5}
    sliceA := slice[:] // {1, 2, 3, 4, 5}
    sliceB := slice[1:3] // {2, 3}
    n:= copy(sliceA, sliceB) //sliceA:{2 3 3 4 5} sliceB:{3, 3} n: 2
    

    注意

    • 如果切片长时间引用大数组中很小的片段,建议新建独立切片,复制出所需数据,以便于原数组内存被及时回收。

    相关文章

      网友评论

          本文标题:Golang笔记(一):数组与切片

          本文链接:https://www.haomeiwen.com/subject/bnoezxtx.html