深入解析Go-Slice
Willem97 · · 968 次点击 · · 开始浏览Slice
一个slice是一个数组某个部分的引用,在内存里,它是一个包含3个域的结构体:指向slice中第一个元素的指针,slice的长度,以及slice的容量。
数组的slice并不会是实际复制一份数据,只是创建一个新的数据结构,包含另外的一个指针,一个长度和一个容量数据。
由于slice是不同于指针的多字长结构,分割操作并不需要分配内存。
底层的实现(usr/loca/src/runtime/slice.go)
// Go 1.12.9
type slice struct {
array unsafe.Pointer // 指向数组的指针
len int // 长度
cap int // 容量
}ptr指针指向的底层是个数组,本质上就是使用Slice这个"引用"对数组进行操作。
slice的扩容
在对slice进行append等操作时,可能会造成slice的自动扩容。其扩容的大小增长规则是:
- 如果新的大小(cap)是当前大小(cap)的2倍以上,则大小增长为新大小
- 否则循环以下操作:如果当前大小(cap)小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新(cap)大小。
Go有两个数据结构创建函数:new和make。new返回一个指向已清零内存的指针,而make返回一个复杂的结构。
slice与unsafe.Pointer相互转换
var o []byte
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&o)))
sliceHeader.Cap = length
sliceHeader.Len = length
sliceHeader.Data = uintptr(ptr)Slice VS Array
在Go中,slice是值(value),非指针,非引用。
Unlike in C/C++ (where arrays act like pointers) and Java (where arrays are object references), arrays in Go are values. This has a couple of important implications: (1) assigning one array to another copies all of the elements, and (2) if you pass an array to a function, it will receive a copy of the array (not a pointer or reference to it).
对于数组:
- 当数组分配给另一个副本时会复制所有元素;
- 数组传递给函数是值传递。
建议在平常使用中用slice而非array,因为当使用非常多的数组时,其大量的副本,导致内存使用率很低。在Go语言的标准库中,API都是使用的slice。
Overall, slices are cleaner, more flexible, and less bug-prone than arrays, so you should prefer using them over arrays whenever possible.
参考链接
https://juejin.im/post/6861890380888014862#heading-1
https://www.godesignpatterns.com/2014/05/arrays-vs-slices.html
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
Slice
一个slice是一个数组某个部分的引用,在内存里,它是一个包含3个域的结构体:指向slice中第一个元素的指针,slice的长度,以及slice的容量。
数组的slice并不会是实际复制一份数据,只是创建一个新的数据结构,包含另外的一个指针,一个长度和一个容量数据。
由于slice是不同于指针的多字长结构,分割操作并不需要分配内存。
底层的实现(usr/loca/src/runtime/slice.go)
// Go 1.12.9
type slice struct {
array unsafe.Pointer // 指向数组的指针
len int // 长度
cap int // 容量
}ptr指针指向的底层是个数组,本质上就是使用Slice这个"引用"对数组进行操作。
slice的扩容
在对slice进行append等操作时,可能会造成slice的自动扩容。其扩容的大小增长规则是:
- 如果新的大小(cap)是当前大小(cap)的2倍以上,则大小增长为新大小
- 否则循环以下操作:如果当前大小(cap)小于1024,按每次2倍增长,否则每次按当前大小1/4增长。直到增长的大小超过或等于新(cap)大小。
Go有两个数据结构创建函数:new和make。new返回一个指向已清零内存的指针,而make返回一个复杂的结构。
slice与unsafe.Pointer相互转换
var o []byte
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&o)))
sliceHeader.Cap = length
sliceHeader.Len = length
sliceHeader.Data = uintptr(ptr)Slice VS Array
在Go中,slice是值(value),非指针,非引用。
Unlike in C/C++ (where arrays act like pointers) and Java (where arrays are object references), arrays in Go are values. This has a couple of important implications: (1) assigning one array to another copies all of the elements, and (2) if you pass an array to a function, it will receive a copy of the array (not a pointer or reference to it).
对于数组:
- 当数组分配给另一个副本时会复制所有元素;
- 数组传递给函数是值传递。
建议在平常使用中用slice而非array,因为当使用非常多的数组时,其大量的副本,导致内存使用率很低。在Go语言的标准库中,API都是使用的slice。
Overall, slices are cleaner, more flexible, and less bug-prone than arrays, so you should prefer using them over arrays whenever possible.
参考链接
https://juejin.im/post/6861890380888014862#heading-1
https://www.godesignpatterns.com/2014/05/arrays-vs-slices.html