当前位置:   article > 正文

golang slice_golang slice 初始化

golang slice 初始化

golang slice
1、slice是什么


   slice译作“切片”。它非常类似数组,通过下标进行访问。我们都知道slice是建立在数组上的,操作起来比数组更灵活

2、slice源码 (runtime/slice.go)


type slice struct {
    array unsafe.Pointer  // 元素指针
    len   int  // 长度
    cap   int  // 容量
}
array 就是指向下层数组的指针
len 长度  切片访问元素时,下标不能超过len大小  len长度最大长度也就等于容量
cap 容量  也是slice能扩张到的最大限度。

3、slice的创建


   1、直接声明
      var s1 []int
   2、new
      s2 := *new([]int)
   3、字面量
      s3 := []int{1,3,5,7}
   4、make
      s4 := make([]int,5,11)
   5、从切片或者数组截取
      s5 := s4[1:]


4、直接声明


   一定注意,此时声明的切片其实是nil切片。它的长度和容量都是0.
   验证:
      var s1  []int
   println(s1 == nil)
   此时打印结果为: true

   另外还有一种切片叫空切片,empty slice,即长度和容量也都为0,但是其数组指向地址是 0xc42003bda0
   empty slice和nil的对比结果为false

   var s1  []int
   var s2 = []int{}
   println(s1 == nil) // 打印结果为:true
   println(s2==nil)   // 打印结果为: false

官方推荐使用nil切片

5、字面量


      var s3 = []int{1,3,5,7,10:98}  // 注意10:98表示下标为10 的元素赋值是98
   fmt.Println(s3)
   // 打印结果是 [1 3 5 7 0 0 0 0 0 0 98]


6、make方式


   需要传入类型,长度,容量
   s5 := make([]int, 5, 8)
   s5[4]=10
   fmt.Println(s5[4])


7、从切片或者数组截取


   s5 := make([]int, 5, 8)
   s6:=s5[:3]
   s6[0]=11  // 此时s5 s6共用底层的数组,s5改变了数组的0号索引的数据,
            // 所以切片s6获取0号索引得到的数据不再是0,而是11了

   fmt.Println(s5[0])// 打印结果 11
   fmt.Println(s6[0])// 打印结果 11

8、make和new的拉扯

make()比new()函数多一些操作,new()函数只会进行内存分配并做默认的赋0初始化,而make()可以先为底层数组分配好内存,然后从这个底层数组中再额外生成一个slice并初始化。另外,make只能构建slice、map和channel这3种结构的数据对象,因为它们都指向底层数据结构,都需要先为底层数据结构分配好内存并初始化。

每一个slice结构都由3部分组成:容量(capacity)、长度(length)和指向底层数组某元素的指针,它们各占8字节(1个机器字长,64位机器上一个机器字长为64bit,共8字节大小,32位架构则是32bit,占用4字节),所以任何一个slice都是24字节(3个机器字长)。

Pointer:表示该slice结构从底层数组的哪一个元素开始,该指针指向该元素
Capacity:即底层数组的长度,表示这个slice目前最多能扩展到这么长
Length:表示slice当前的长度,如果追加元素,长度不够时会扩展,最大扩展到Capacity的长度(不完全准确,后面数组自动扩展时解释),所以Length必须不能比Capacity更大,否则会报错


网上很多种解读,但是最终要的一点是:
    有两个切片,s2是s1的衍生,但随着s2不断append,如果你append 的数据超过了slice的容量(capacity).那么必然会导致一个新的slice生成,两次之后二者就“脱节”了,之后对一个的元素改动就不能同步到另一个了。此时的slice地址id和原来那个slice不一样。
    

 

  1. package main
  2. import "fmt"
  3. func main() {
  4. //orig := make([]int, 4, 7)
  5. orig := []int{1,2,3,4}
  6. fmt.Println("processIt before -->", orig, "cap is ", cap(orig))
  7. ret := processIt(orig)
  8. //processIt(orig)
  9. fmt.Println("processIt after ret-->", ret)
  10. fmt.Println("processIt after orig -->", orig)
  11. }
  12. func processIt(l []int) []int{
  13. fmt.Println("processIt start -->", l)
  14. l[0]=888
  15. //l[0]=100
  16. l = append(l, 100,101,102)
  17. l[6]=999
  18. fmt.Println("processIt end -->", l)
  19. return l
  20. }


输出结果:

processIt before --> [1 2 3 4] cap is  4
processIt start --> [1 2 3 4]
processIt end --> [888 2 3 4 100 101 999]
processIt after ret--> [888 2 3 4 100 101 999]
processIt after orig --> [888 2 3 4]

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/206383?site
推荐阅读
相关标签
  

闽ICP备14008679号