美文网首页走进迈莫
go 数组和切片slice那些事儿

go 数组和切片slice那些事儿

作者: 迈莫coding | 来源:发表于2021-01-16 11:23 被阅读0次

    目录

    • 数组
      • 数组概念
      • 数组的初始化
    • 切片
      • slice概念
      • slice创建
      • slice追加
      • slice拼接问题
      • slice作为函数参数
      • slice的扩容
    • 数组和切片slice异同
    • 闲聊
    • 【迈莫coding】

    数组

    数组概念

    Go语言数组中每个元素都是按照索引来访问的,索引从0到数组长度减一。Go语言中len()函数可以返回数组中的元素个数。

    数组的初始化

    • 关键字 var 创建数组
    package main
    
    import "fmt"
    
    func main() { 
      var a [3]int // 三个整数型数组 
      fmt.Println(a) 
      
      var b = [...]int{6, 7, 8} // 不声明长度
      fmt.Println(b) 
    }
    

    结果

    [0 0 0]
    [6 7 8]
    
    • 自动初始化
    package main
    
    import "fmt"
    
    func main() {
      a := [4]int{2, 0, 2, 1}
      fmt.Println(a) // [2 0 2 1]
      
      b := [...]int{2, 0, 2, 1} // 不声明长度
      fmt.Println(b) // [2 0 2 1]
      
      c := [...]int{3:-1} // 指定索引位置值
      fmt.Println(c)
    }
    

    结果

    [2 0 2 1]
    [2 0 2 1]
    [0 0 0 -1]
    

    切片slice

    slice概念

    slice是一个结构体,它本身并非动态数组或数组指针。它内部通过指针引用底层数组,设定相关属性将数据读写操作限定在指定区域内。它包含三个成员:len,cap,array,分别表示切片的长度,切片的容量,切片的底层数组的地址。

    slice创建

    这里说一个比较难懂的切片创建及其原理

    package main
    import "fmt"
    
    func main() {
      x := [...]int{10, 30, 20, 50, 80, 90, 100}
      fmt.Println(x[2:4:6])
    }
    

    属性示意图:

    在这里插入图片描述

    由图可知,x[2:4:6]表示的切片含义:slice的长度为2,容量为4的切片。

    计算公式:

    • len: high - low,对应示例为(4 - 2 = 2)
    • cap: max - low,对应示例为(6 - 2 = 4)

    slice追加

    package  main
    
    import "fmt"
    
    func main() {
      s := make([]int, 5)
      s = append(s, 1, 2, 3)
      fmt.Println(s)
    }
    

    结果

    [0 0 0 0 0 1 2 3] // make初始化默认为0
    

    slice拼接问题

    package main
    
    import "fmt"
    
    func main() {
      a := []int{1, 2, 3}
      b := []int{4, 5, 6}
      a = append(a, b...)
      fmt.Println(a)
    }
    

    注意
    两个slice进行拼接时,记住要将第二个参数后面加上 ... ,否则会编译失败。

    结果

    [1 2 3 4 5 6]
    

    slice作为函数参数

    在go语言中,函数参数传递只有值传递,没有引用传递。

    所以当slice作为函数参数传递时,他也是传递的是原切片的副本。如果直接传slice的话,实参不会被调用函数中的操作而改变;若传递的是slice指针的话,实参是会被影响的。

    值得注意的是,不管是指针传递还是值传递,如果改变来slice底层数组中的值,
    那么会影响到实参slice中的底层数据。

    来一起看个例子:

    package main 
    
    import "fmt"
    
    func copys(a []int) {
      // v只是一个副本,不能改变s中元素的值
      /* for _, v := range a {
        v++
      }
      */
      
      for i, _ := range a{
        a[i] += 1
      }
    
    }
    
    func main() {
      s := []int{1, 2, 3}
      copys(s)
      fmt.Println(s)
    }
    

    结果

    [2 3 4]
    

    slice的扩容

    当调用append函数向切片尾部(slice[len])添加数据时,如超出cap限制,则会为新切片对象重新分配数组。

    package main
    
    import "fmt"
    
    func main() {
      s := make([]int, 0, 100)
      s1 := s[:2:4]
      s2 := append(s1, 1, 2, 3, 4, 5, 6)
      
      fmt.Printf("s1: %p: %v\n", &s1[0], s1)
      fmt.Printf("s2: %p: %v\n", &s2[0], s2)
      
      fmt.Printf("s data: %v\n", s[:10])
      fmt.Printf("s1 cap: %d, s2 cap: %d\n", cap(s1), cap(s2))
      
    }
    

    结果

    s1: 0xc000102000: [0 0]
    s2: 0xc00001a040: [0 0 1 2 3 4 5 6] // 数组地址不同,确认新分配
    s data: [0 0 0 0 0 0 0 0 0 0]       // append 并未向愿数组写入部分数组
    s1 cap: 4, s2 cap: 8                // 新数组是新cap 的2倍
    

    注意

    • 是超过切片cap限制,而非底层数组长度限制,因为cap可小于数组长度。
    • 当原slice容量小于1024时,新slice容量是原slice容量的2倍;原slice容量大于1024时,新slice容量大于等于原容量的2倍或1.25倍。

    数组和切片slice异同

    数组 切片slice
    长度 初始化指定长度 长度动态 不固定
    创建方式 make创建

    闲聊

    • 读完文章,自己是不是和数组/slice的cp率又提高了
    • 我是迈莫,欢迎大家和我交流

    文章也会持续更新,可以微信搜索「 迈莫coding 」第一时间阅读。

    相关文章

      网友评论

        本文标题:go 数组和切片slice那些事儿

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