首页 > 其他分享 >golang slice

golang slice

时间:2023-11-15 14:12:31浏览次数:28  
标签:扩容 slice int cap len golang 数组

slice 是 golang 的切片,动态数组

底层结构

// runtime/slice.go
type slice struct {
	array unsafe.Pointer // 底层数组
	len   int
	cap   int
}

golang 的 slice 底层是一个数组,也就是可以通过 &s[0]来获取底层数组的地址,len 记录的当前,cap 记录的是底层数组的大小也就是当前 slice 的容量

初始化

var num1 []int // num1此时为 nil
num2 := make([]int,4) //len = 4 cap = 4
num3 := make([]int,3,7) // len = 3 cap = 7
num4 := []int{1,2,3} // len = 3 cap = 3

或从另一个slice新建

s1 := []int{1,2,3,4,5} // s1 len = 5 cap = 5
s2 := s1[:] // s2 len = 5 cap = 5
s3 := s1[:3] // s3 len = 3 cap = 5
s4 := s1[:2:4] // s4 len = 2 cap = 4

以上的 s2,s3,s4 底层数组指向的都是 s1 的底层数组起始位置

函数传参

slice 作为函数传参时候传递的是 slice 的 struct 的拷贝,但是底层数组是作为struct 内部的一个变量是不变的,所以在函数间传递时候更改 slice 的某些变量会影响原 slice

扩容

在 slice 调用 append 方法时,如果添加后的容量大于 cap,那么就会发生扩容

扩容规则

在1.18版本之前
当原 cap < 1024 时候,每次扩容会扩容成两倍;当 cap > 1024 时候,会扩容成原容量的 1.25 倍
在1.18 版本之后
当原 cap < 256 时候,每次扩容会扩容成原容量的两倍;当 cap > 256,会扩容成原容量的 newcap = oldcap+(oldcap+3*256)/4 倍,所以当原容量是 256 时,也会扩容成 512;但是在实际扩容过程中不会精确地这个值,通常会进行一次内存对齐,所以会有出入;

扩容过程

先申请 newcap 大小的数组,然后把原数组全量拷贝过去,然后再进行其他的操作

难点

slice 的难点主要是还是传参,和传参后的 append 触发扩容
基本原则就一个,没发生扩容的情况下,会改变原数组;如果发生扩容,则不会改变原数组

参考

数组与切片有什么异同

标签:扩容,slice,int,cap,len,golang,数组
From: https://www.cnblogs.com/elve960520/p/17833696.html

相关文章

  • golang版本升级(Mac GoLand版)
    本地的go版本是1.18,想升级到1.21,运用GoLand做快速升级第一步  进入GoLand-》Preferences第二步  进入Go-〉GOROOT点击“+”号,选择“Download”第三步选择需要更新的版本 点击“OK”后“Apply”,最新版的go就会下载到你的GOPATH里面了 升级完新版本后,deb......
  • Golang workSpace工作区
    创建myworkspace主项目mkdirmyworkspacecdmyworkspace创建common子项目mkdircommon&&cdcommongomodinitcommonvimcommon.gomyworkspace/common/common.gopackagecommonimport"fmt"funcDosomething(){fmt.Println("dosomet......
  • JavaScript slice 方法用法与实例解析
    在JavaScript中,slice()是一个常用的数组方法,用于从现有数组中提取一部分元素,然后返回一个新的数组。它是一个非常有用的工具,可以帮助你在不改变原始数组的情况下操作数组的子集。本文将介绍slice()的基本概念、使用方法、实践案例和互动练习,以帮助你更好地理解和掌握这一功能......
  • Golang反射
    反射的结构体//reflect/type.gotypeTypeinterface{//该类型内存分配大小(内存对齐单位子节) Align()int //该类型作为结构体字段时内存分配大小(内存对齐单位子节) FieldAlign()int//根据indexin[0,NumMethod())获取方法按lexicographic排序 Method(i......
  • 关于Golang三个内存区域的形象比喻
    当我们使用Go语言编写程序时,可以将这三个内存区域类比为一个大的游乐场。Arena区就像是整个游乐场的主要区域,它是用于分配和管理大对象的地方。在这个区域,我们可以找到各种大型游乐设施,比如大型滑梯、蹦床和攀爬架等。这些设施需要更多的空间和资源来支持,因此它们被分配在Arena区域......
  • Golang内存泄漏的代码示例
    以下是几个可能导致内存泄漏的Go代码示例:资源未关闭:funcreadFile(){ file,err:=os.Open("filename.txt") iferr!=nil{ //错误处理 return } //使用file进行读取操作 //...}在上述代码中,readFile函数打开了一个文件,但没有在使用完后调用file.Close()来关闭文......
  • Golang select语句代码示例
    在Go语言中,select语句用于多路选择(multiplexing),允许在多个通信操作中选择可用的操作进行执行。select语句的语法如下:select{case<-channel1://当channel1有数据可读时执行的代码casedata:=<-channel2://当channel2有数据可读时执行的代码,同时将读取的数据存储在......
  • Golang 无缓冲channel有哪些特点?
    无缓冲channel是Go语言中的一种特殊类型的channel,其主要特点是在发送和接收数据时要求发送方和接收方必须同时准备好,否则会造成阻塞。具体来说,当一个无缓冲channel的发送操作没有准备好时,会阻塞发送方的执行;同样地,当一个无缓冲channel的接收操作没有准备好时,会阻塞接收方的执行。无......
  • Golang中如何使用new函数创建一个结构体对象?
    在Go语言中,可以使用new函数创建一个结构体对象的指针。下面是使用new函数创建结构体对象的示例:typePersonstruct{NamestringAgeint}funcmain(){//使用new函数创建一个Person结构体对象的指针p:=new(Person)//设置结构体对象的字段值......
  • Golang 锁
    写锁需要阻塞写锁:一个协程拥有写锁时,其他协程写锁定需要阻塞写锁需要阻塞读锁:一个协程拥有写锁时,其他协程读锁定需要阻塞读锁需要阻塞写锁:一个协程拥有读锁时,其他协程写锁定需要阻塞读锁不能阻塞读锁:一个协程拥有读锁时,其他协程也可以拥有读锁......