美文网首页
Go slice那些事

Go slice那些事

作者: 海边码字 | 来源:发表于2019-05-17 23:38 被阅读0次

今晚闲来无事,总结一下Go的slice

slice是什么
slice在Go中的原型?
slice类似数组,是一种定长的数组。在底层slice是这样的:
type slice struct {
array unsafe.Pointer
len int
cap int
}

如何创建slice
1.创建nil slice
var lst []int

2.创建无容量的空slice
lst := make([]int, 0, 0)

3.创建有容量的空slice
lst := make([]int, 0, 6)

4.创建零值slice(10个0)
lst := make([]int, 10)

5.用引用创建slice
lst := array[:]

slice的其他操作函数
len(lst) 获得slice的长度
cap(lst) 获得slice的容量
append(lst, 6) 给lst添加1个数字6
append(lst, lst2…) 给lst添加一个slice,lst2是一个slice
copy(lst, srcList) //拷贝srcList中内容到lst中去,仅能拷贝len(lst)个元素

部分细节陷阱
1.函数形参为slice
函数形参传递slice是值传递,并不是引用传递,在函数中修改形参的值,并不会影响函数外的传入的slice
解决办法
(1):传入slice指针
func modify(lst *[]int) {
//修改lst
}

(2):函数内修改了slice后返回
func modify(lst []int) []int {
//修改lst

return s

}

(3):将函数作为slice的指针
type sliceInt []int
func(this *sliceInt) modify() {
//修改lst
}

2.数据同源
func main() {
lst := [2]int{}
lst[0] = 1

fmt.Printf("lst: %v , len: %d, cap: %d\n", lst, len(lst), cap(lst))

dlst := lst[0:1]
dlst[0] = 5

fmt.Printf("lst: %v ,len: %d, cap: %d\n", lst, len(lst), cap(lst))
fmt.Printf("dlst: %v, len: %d, cap: %d\n", dlst, len(dlst), cap(dlst))

}

输出如下
lst: [1 0] , len: 2, cap: 2
lst: [5 0] ,len: 2, cap: 2
dlst: [5], len: 1, cap: 2

原因:dlst会指向来源于lst,底层数据指针是指向lst的,修改dlst的数据也同时会修改lst的数据。

3.slice扩容陷阱
func main() {
lst := [2]int{}
lst[0] = 1

fmt.Printf("lst: %v , len: %d, cap: %d\n", lst, len(lst), cap(lst))

dlst := lst[0:1]
dlst = append(dlst, []int{2, 3}...)
dlst[1] = 1

fmt.Printf("lst: %v ,len: %d, cap: %d\n", lst, len(lst), cap(lst))
fmt.Printf("dlst: %v, len: %d, cap: %d\n", dlst, len(dlst), cap(dlst))

}

输出如下:
lst: [1 0] , len: 2, cap: 2
lst: [1 0] ,len: 2, cap: 2
dlst: [1 1 3], len: 3, cap: 4

原因:因为存储空间不够,需要扩容,dlst会被分配新的空间,所以此时修改dlst数据并不会改变lst中的源数据。因为dlst数据指针已经不再指向源数据地址。

Empty Slice和Nil Slice和零slice
1.零slice
lst := make([]int, 10)
10个零值slice

2.空Slice
lst := make([]int, 0)
没有长度和容量的slice

3.nil Slice
var lst []int
此时lst是一个nil的slice,底层数据 len:0,cap:0,*Elem:nil
注:可以对nil的slice 使用append操作。

扩容策略
append的扩容规则为:
1.如果新申请容量大于2倍的旧容量,最终容量就是新申请的容量;否则执行第2步
2.如果旧切片的长度小于1024,则最终容量就是旧容量的两倍,否则执行第3步
3.如果旧切片长度大于等于1024,则最终容量从旧容量开始循环增加原来的 1/4,即直到最终容量大于等于新申请的容量
4.如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)

注:具体的代码参考go目录 src/runtime/slice.go中的growslice函数。

文章也同步发在了个人网站上
http://www.seabytelab.com/go-slice-lite.html

相关文章

  • Go slice那些事

    今晚闲来无事,总结一下Go的slice slice是什么slice在Go中的原型?slice类似数组,是一种定长的...

  • Go 中 slice 的那些事

    一、定义 我们都知道在 Go 语言中,数组的长度是不可变的,那么为了更加灵活的处理数据,Go 提供了一种功能强悍的...

  • Go语言——Slice分析

    Go语言——Slice分析 源码很不好找,在go\src\runtime\slice.go。 根据容量cap*元素...

  • 深入理解 Go Slice

    原文地址:深入理解 Go Slice 是什么 在 Go 中,Slice(切片)是抽象在 Array(数组)之上的特...

  • Go编程基础(array、slice、map和struct)

    这篇讲解go语言中数据存储类型array、slice、map和struct,要清楚它们那些是值传递,那些是指针传递...

  • Go array、slice、map和struct的对比

    这篇讲解go语言中数据存储类型array、slice、map和struct,要清楚它们那些是值传递,那些是指针传递...

  • Go Slice 最大容量大小是怎么来的

    原文地址:Go Slice 最大容量大小是怎么来的 前言 在《深入理解 Go Slice》中,我们提到了 “根据其...

  • 彻底理解Golang Slice

    看完这篇文章,下面这些高频面试题你都会答了吧 Go slice的底层实现原理 Go array和slice的区别 ...

  • go slice

    切片创建和初始化 slice := make([]string, 5) slice := make([]int,3...

  • go slice

网友评论

      本文标题:Go slice那些事

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