教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang Slice

Golang Slice

发布时间:2022-01-26   编辑:jiaochengji.com
教程集为您提供Golang Slice等资源,欢迎您收藏本站,我们将为您提供最新的Golang Slice资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg><h2>Slice介绍</h2>

Slice也叫做切片,是golang中最为常用的一个结构之一,跟数组相比,它更加灵活便利,拥有自动扩容策略,但是也存在着一些比较容易被忽略的坑点,文章会先介绍Slice的基本使用方式,接着会介绍Slice的内部实现,最后会总结一些我遇到过的坑点(这一点可能会持续更新)~

<h3>
使用方式</h3> <h4>Slice切片初始化</h4>

slice的初始化和数组的初始化方式特别相似,但是这是两种完全不同的数据结构,数组的容量大小是不允许被调整的。

<pre><code>//slice的初始化 s2 := []int{} s3 := []int{1, 2, 3} s4 := make([]int, 0, 10) //预分配一些容量,make的第二个参数为len,第三个参数为capacity //数组初始化 s5 := [3]int{1, 2, 3} s6 := [...]int{1, 2, 3} //自动推导 </code></pre> <h4>
基本操作</h4> <pre><code>s1 := make([]int, 10) //make时指定len时会给定默认值,如果打印s1,输出结果是10个0,感兴趣可以试一试 //slice的遍历 for index, value := range s1 { //do something } //slice追加 s1 := append(s1, 1) //清空slice s1 := s1[0:0] //获取slice的长度 length := len(s1) //获取slice的容量 capacity := cap(s1) //获取slice子串 s2 := s1[0:10] //这里是左闭右开的原则 //将s1或s1的字串追加到s2中 s2 := append(s2, s1[0:10]...) //...是一个操作符,会将整个切片拆开append到s2中 </code></pre> <h3>slice的内部结构</h3>

在运行时切片的结构使用如下SliceHeader表示的,分别有指向数组的指针、切片长度、切片容量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k4r5GrYQ-1594266842810)(https://yunpan.oa.tencent.com/note/api/file/getImage?fileId=5f06916e6f0b9316e2670201)]

<pre><code>type SliceHeader struct { Data uintptr //指向数组的指针 Len int //切片长度 Cap int //切片容量 } </code></pre> <h3>
slice自动扩容机制</h3> <ol><li>如果期望容量大于当前容量的两倍就会使用期望容量;</li><li>如果当前切片容量小于 1024 就会将容量翻倍;</li><li>如果当前切片容量大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;</li></ol><h3>坑点</h3> <ol><li>Slice并没有提供官方的函数可供查询某元素是否存在,所以只能手动遍历Slice;</li><li>在使用Slice时如果没有预估容量,可能会带来很大的扩容开销,如果是在高并发场景下,一定要记得预估capacity并提前预创建</li><li>删除一个Slice中的元素是一件比较麻烦的事情</li><li>Slice赋值为浅拷贝,这一点特别值得注意。在没有扩容的情况下,复制后的切片和原始切片指向的数组将是同一个,操作两者都会操作同一个底层数组,并改变自己的len和cap,而另一个切片的结构信息不会改变;有扩容的情况下,复制后的切片会指向一个新的数组,gc不会将原来的数组清理掉。</li></ol><h4>Slice赋值问题</h4> <pre><code>package main import "fmt" func main() { data := make(map[string][]int32) item0 := make([]int32, 0) item0 = append(item0, 1) item0 = append(item0, 2) data["item0"] = item0 // 获取到item0, 并向其中添加两项 temp := data["item0"] temp = append(temp, 3) temp = append(temp, 4) // 输出结果是:temp len is 4, data["item0"] len is 2 // 这里返回的temp,是一个data["item0"]的副本,内部指向同一个底层数组 //其实此时他们已经指向不同的底层数组了,因为原始的cap只有2(可以推断),再append元素将自动扩容到4,temp也会指向不同的地址;其实很容易想到,在这一点上可能存在一些隐患 fmt.Printf("temp len is %v, data[\"item0\"] len is %v\n", len(temp), len(data["item0"])) } </code></pre> 到此这篇关于“Golang Slice”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang中的空slice
U3D笔试题1:golang实现
Golang语言slice实现原理及使用方法
Golang 切片(slice)扩容机制源码剖析
go(golang)之slice的小想法1
golang读取接口数据interface{}
[go语言]-slice实现的使用和基本原理
golang 函数传多个参数_Golang中的参数传递示例详解
Golang slice 切片原理
Golang 深入 slice 实现原理及使用技巧

[关闭]
~ ~