首页 > 其他分享 >Golang Slice

Golang Slice

时间:2023-02-25 13:14:11浏览次数:29  
标签:扩容 切片 Slice 容量 Golang 数组 拷贝

Golang—Slice

Slice是Go语言中的一种数据类型,又称动态数组,依托数组实现,可以方便的进行扩容、传递等,实际使用中比数组更灵活。

实现原理

Slice依托数组实现,底层数组对用户屏蔽,在底层数组容量不足时可以实现自动重分配并生成新的Slice。

img

扩容

slice的扩容可以分为以下两种情况:

  1. 原slice的容量够用
    这种情况下,扩容以后的指针还是指向原来的数组,对一个slice的操作可能影响多个指针指向相同地址的 Slice。
    img
  2. 原slice的容量不够用
    如果原来数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区 域,把原来的值拷贝过来,然后再执行 append() 操作。也就是说这是2块不同的内存地址,相互不影响。
    (这里我只是做个示范,并不代表就一定会扩容2个cap,具体的扩容还需要按照扩容规则来)
    img

具体扩容规则

规则1

  • 需要的容量大于原切片容量的两倍时,会使用需要的容量作为新容量;
  • 当原切片长度小于1024时,新切片的容量会直接翻倍;
  • 而当原切片的容量大于等于1024时,会反复地增加25%,也就是变为原来容量的1.25倍,直到新容量超过所需要的容量。

规则2

  • 如果扩容之后还没有超过原数组的容量,那切片中的指针指向的位置还是原数组;
  • 如果扩容之后超过了原数组的容量,那就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。

使用append()向Slice添加一个元素的实现步骤如下:

  1. 假如Slice容量够用,则将新元素追加进去,Slice.len++,返回原Slice
  2. 原Slice容量不够,则将Slice先扩容,扩容后得到新Slice
  3. 将新元素追加进新Slice,Slice.len++,返回新的Slice。

总而言之,扩容只关心的slice的cap,长度是跟着append进行变化的。

深浅copy

  1. 深拷贝:拷贝的是数据本身,创造一个新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值

实现深拷贝的方式:

  • copy(slice2, slice1)
    • 并且使用copy()内置函数拷贝两个切片时,会将源切片的数据逐个拷贝到目的切片指向的数组中,拷贝数量取两个切片长度的最小值,多余的则会丢失。也就是说copy过程中不会发生扩容。
    • 例如下图(slice2中的9,10则会丢失)
      img
  • 遍历append赋值
  1. 浅拷贝:拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化

实现浅拷贝的方式:

引用类型的变量,默认赋值操作就是浅拷贝

slice2 := slice1

Slice总结

  1. 每个Slice底层都是由一个array来进行维护。
  2. slice的扩容需要根据实际情况进行实际判断。
  3. 使用append()向切片追加元素时有可能触发扩容,扩容后将会生成新的切片

标签:扩容,切片,Slice,容量,Golang,数组,拷贝
From: https://www.cnblogs.com/Asakalan/p/17154174.html

相关文章

  • golang-小技巧:struct嵌套
    gostruct1typeastruct{2namestring3agestring4}56typebstruct{7a//匿名嵌套结构体8na......
  • golang 映射(map)
    1.映射的定义map是一种无序的基于key-value的数据结构,Go语言中map是引用类型,必须初始化(make)才能使用。map定义:map[KeyType]ValueType其中,KeyType表示键的类型,ValueTyp......
  • golang-小技巧:slice与sort包
    s1:=make([]string,2)s1[0]="good"s1[1]="morning"//根据val寻找下标i:=sort.SearchStrings(s1,"morning")fmt.Println(i)so......
  • golang 切片
    1.切片的定义切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。切片的使用与数组类似,遍历,访问切片元素等都一样。切片是长度是可以变化的,因此切片可以看做......
  • golang入门(十三)并发锁
    如果程序用到的数据是多个groutine之间的交互过程中产生的,那么使用上文提到的channel就可以解决了。如果我们的使用多个groutine访问和修改同一个数据,就需要考虑在并发环境......
  • 使用golang和bluge打造自己的全文搜索引擎
    全文搜索引擎有许多,其中最出名的是elasticsearch,无论是性能还是体验都是最顶尖的,但是对小应用来不友好,因为小应用的硬件资源比较少,所以能够通过库/模块的方式内置在应用中......
  • golang WEB框架Hertz --- 获取参数
    安装Hertz命令行工具请确保您的Go版本在1.15及以上版本,笔者用的版本是1.18配置好GO的环境后,按照Hertz的命名行工具goinstallgithub.com/cloudwego/hertz/cmd/hz@lates......
  • golang 字符串函数
    1.统计字符串的长度,按字节进行统计packagemainimport"fmt"funcmain(){ vars1string="hello,世界" fmt.Printf("s1字符串的长度为:%v",len(s1))//汉字为......
  • golang 解析json数据
       packagemainimport(jsoniter"github.com/json-iterator/go")funcString2Bytes(datastring)[]byte{return[]byte(data)}funcmain(){......
  • golang入门(十二)并发channel
    多线程与多进程本质的区别在于,多线程的内存空间是共享的,多进程是每一个进程都会独立开辟一块内存空间。如果我们运行的多个任务是完全独立的,那么在资源足够的情况下并发还是......