深入解析Go-Slice

韩瑶
• 阅读 2084

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

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java ArrayList集合
ArrayList集合是程序中最常见的一种集合,它属于引用数据类型(类)。在ArrayList内部封装了一个长度可变的数组,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素,因此可以将ArrayList集合看作一个长度可变的数组。集合的创建格式导包:importjava.util.ArrayList;
九路 九路
4年前
一篇文章彻底弄懂理解和高效运用切片(slice)
slice,中文多译为“切片”,是Go语言在数组之上提供的一个重要的抽象数据类型。在Go语言中,绝大多数需要使用数组的场合,切片都实现了完美替代。并且和数组相比,切片提供了更通用、功能更强大且便捷的数据序列访问接口。1.切片究竟是什么在对切片一探究竟之前,我们先来简略了解一下Go语言中的数组。Go语言数组是一个固定长度的、容纳同构类型元素的
Souleigh ✨ Souleigh ✨
4年前
JS 实现单链表
要存储多个元素,数组(或列表)可能是最常用的数据结构。但这种数据结构有一个缺点:(在大多数语言中)数据的大小是固定的,从数组的起点或中间插入或移除项的成本很高。  链表存储有序的集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。  相对于传统的数组,链表的一个好处是
虾米大王 虾米大王
2年前
java代码095
code095.jspEL表达式访问数组<%Stringarr2(String)request.getAttribute("book");for(inti0;i$index:$bookindex
Kevin501 Kevin501
4年前
Go语言中new()和make()的区别
1.Go语言中的值类型和引用类型值类型:int,float,bool,string,struct和数组(数组要特别注意,别搞混了)变量直接存储值,分配栈区的内存空间,这些变量所占据的空间在函数被调用完后会自动释放。引用类型:slice,map,chan和值类型对应的指针变量存储的是一个地址(或者理解为指针),指针指向内存中真
Wesley13 Wesley13
3年前
Go 定长的数组
1.Go语言数组的简介  几乎所有的计算机语言都有数组,应用非常的广泛。同样,在Go语言中也有数组并且在数组的基础上还衍生出了切片(slice)。数组是一系列同一类型数据的集合,数组中包含的每个数据被称为数组元素,一个数组包含的元素个数被称为数组的长度,这是数组的基本定义。  在Go语言中数组是一个值类型(ValueType)
Stella981 Stella981
3年前
JSONArray数据转换成java List
<divid"cnblogs\_post\_body"class"blogpostbody"<p<spanstyle"fontsize:18pt"1.后台接收json数组转成封装实体类的List:</span</p<divclass"cnblogs\_code"<divclass"cnblogs\_code\_tool
Stella981 Stella981
3年前
Golang高效实践之array、slice、map实践
前言Golang的slice类型为连续同类型数据提供了一个方便并且高效的实现方式。slice的实现是基于array,slice和map一样是类似于指针语义,传递slice和map并不涉及底层数据结构的拷贝,相当于传递底层数据结构的指针。Arrays数组 数组类型的定义需要指定长度和元素的类型。例如,\4\int表示一个四个整数
Stella981 Stella981
3年前
Android开发的内存问题
不少人认为Java(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.51code.com%2F)程序因为有垃圾回收机制,就不会有内存泄漏。其实如果我们一个程序中已经不再使用某个对象,但是依然有引用指向它,垃圾回收器就没有办法回收它,所以该对象占用的内存就无法被使用,造成内存泄露
菜园前端 菜园前端
2年前
什么是链表?
原文链接:什么是链表?链表是有序的数据结构,链表中的每个部分称为节点。可以首、尾、中间进行数据存取,链表的元素在内存中不必是连续的空间,每个节点通过next指针指向下一个节点。优点链表的添加和删除不会导致其余元素位移。缺点无法根据索引快速定位元素。数组和链
liam liam
1年前
深入解析JavaScript中的slice方法:用法与实例详解
在中,slice()是一个常用的数组方法,用于从现有数组中提取一部分元素,然后返回一个新的数组。它是一个非常有用的工具,可以帮助你在不改变原始数组的情况下操作数组的子集。本文将介绍slice()的基本概念、使用方法、实践案例和互动练习,以帮助你更好地理解和