深入解析Go-Slice

Willem97 · · 620 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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有两个数据结构创建函数:newmakenew返回一个指向已清零内存的指针,而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).

对于数组:

  1. 当数组分配给另一个副本时会复制所有元素;
  2. 数组传递给函数是值传递。

建议在平常使用中用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


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:Willem97

查看原文:深入解析Go-Slice

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

620 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传