go 切片slice学习总结

2024-08-30 21:36
文章标签 go 切片 学习 总结 slice

本文主要是介绍go 切片slice学习总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

切片的结构

切片的底层结构:

type SliceHeader struct {Data uintptr  // 指向底层数组的指针 Len  int      //长度Cap  int      //空间容量
}

切片的初始化

1 通过数组或者已有的slice创建新的slice

1.1 使用数组创建切片

通过数组的一部分来初始化切片。

array := [10]int{0,1, 2, 3, 4, 5,6,7,8,9}  
slice := a[5:7] 

Slice将与原数组共用一部分内存。

1.2 通过slice创建新的切片对象

x := []int{2, 3, 5, 7, 11}  
y := x[1:3]

x:   长度len=5 cap=5 data指针指向长度为5的底层数组结构。

y  长度为2 cap为y底层原始数组结构第一个元素位置到的最后一个容量空间位置的长度即5-1=4

data为指针指向底层原始数组结构第1个元素的地址(索引从0开始)

图示如下:

2,使用make函数

make函数是Go中用于分配和初始化内置类型的内置函数,也可以用来创建切片。

slice := make([]int, 5, 10) // 创建一个长度为5、容量为10的int类型切片

长度为5,即可以使用下标slice[0] ~ slice[4]来操作里面的元素,capacity为10,表示后续向slice添加新的元素时可以不必重新分配内存,直接使用预留内存即可。

3,切片字面量

直接使用切片字面量创建切片。

s := []int{1, 2, 3} // 直接初始化一个切片


4,较特殊的切片:

nil 切片

var a []int 

未初始化的切片默认值为nil

空切片

var b = []int{} 

也叫零值切片。和 nil 不相等, 一般用来表示一个空的集合。len 和 cap 都为 0。空切片在内部拥有一个非nil的、零长度的底层数组


在判断一个切片是否为空时,一般通过 len 获取切片的长度来判断,一般很少将切片和 nil 值做直接的比较

数组与切片

数组截取元素生成切片,共用底层元素存储底层数组结构

func main() {data := [...]int{0, 1, 2, 3, 4, 5}s := data[2:4]s[0] += 100s[1] += 200fmt.Println(s)fmt.Println(data)
}

打印结果:

 [102 203]
 [0 1 102 203 4 5]

 切片赋值

	data := [...]int{0, 1, 2, 3, 4, 5}s2 := data[:]fmt.Println("s2是:", s2)s3 := s2fmt.Println("s3是:", s3)s3[0] = 1000 + s3[0]fmt.Println("s3是:", s3)fmt.Println("s2是:", s2)fmt.Println("data是:", data)

打印结果:

s3是: [1000 1 2 3 4 5]
s2是: [1000 1 2 3 4 5]
data是: [1000 1 2 3 4 5]

切片参数

函数参数是切片时,是引用传递,函数内对切片的改动影响源切片

    func main(){sl := []int{1, 2, 3, 4, 5, 6, 7}PrintElements(sl)fmt.Printf("slice a : %v\n", sl)}func PrintElements(sl []int) {fmt.Println("-------------")for i, v := range sl {fmt.Println(v)sl[i] = v + 1}
}

打印结果:

-------------

 1
2
3
4
5
6
7
slice a : [2 3 4 5 6 7 8]

切片容量

切片扩容

扩容实际上是重新分配一块更大的内存,将原Slice数据拷贝进新Slice,然后返回新Slice,扩容后再将数据追加进去。

例如,当向一个capacity为5,且length也为5的Slice再次追加1个元素时,就会发生扩容,如下图所示:

扩容操作只关心容量,会把原Slice数据拷贝到新Slice,追加数据由append在扩容结束后完成。上图可见,扩容后新的Slice长度仍然是5,但容量由5提升到了10,原Slice的数据也都拷贝到了新Slice指向的数组中。

扩容容量的选择遵循以下规则:

  • 如果原Slice容量小于1024,则新Slice容量将扩大为原来的2倍;
  • 如果原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍;

使用append()向Slice添加一个元素的实现步骤如下:

  • 假如Slice容量够用,则将新元素追加进去,Slice.len++,返回原Slice
  • 原Slice容量不够,则将Slice先扩容,扩容后得到新Slice
  • 将新元素追加进新Slice,Slice.len++,返回新的Slice。

参考:slice-地鼠文档 

切片字面量创建的切片

    slice := []int{1, 2, 3, 4, 5, 6, 7, 8}

当你使用字面量来创建切片时,切片的初始容量(capacity)通常等于其长度(length)。这意味着,例子slice := []int{1, 2, 3, 4, 5, 6, 7, 8},切片的长度和容量都是8。

	slice := []int{1, 2, 3, 4, 5, 6, 7, 8}fmt.Print("cap:", cap(slice))fmt.Print("len:", len(slice))

cap: 8
len: 8 

扩容:

	slice := []int{1, 2, 3, 4, 5, 6, 7, 8}fmt.Println("cap:", cap(slice))fmt.Println("len:", len(slice))fmt.Println("----------append后扩容----------")slice2 := append(slice, 0) // 切片扩展 1 个空间fmt.Println("cap:", cap(slice2))fmt.Println("len:", len(slice2))fmt.Println(&slice[0] == &slice2[0])

 打印结构

cap: 8
len: 8
----------append后扩容----------
cap: 16
len: 9
false

append元素后容量不够使用,扩容为原来的两倍

make创建的切片

make创建的切片,类型申明之后,第一个数值是长度,第二个数值是容量

slice2 := make([]int, 3, 7)fmt.Println("cap:", cap(slice2))fmt.Println("len:", len(slice2))

cap: 7
len: 3

append元素后,容量不够就会扩容为之前的两倍容量。随之是地址的改动。

	slice2 := make([]int, 3, 7)fmt.Println("cap:", cap(slice2))fmt.Println("len:", len(slice2))slice3 := append(slice2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // 切片扩展 1 个空间fmt.Println("----------append后扩容----------")fmt.Println("cap:", cap(slice3))fmt.Println("len:", len(slice3))fmt.Println(&slice2[0] == &slice3[0])

cap: 7
len: 3
----------append后扩容----------
cap: 14
len: 13
false

切片操作

1,append操作

使用append函数,生成新的切片

append函数返回的slice跟原slice是独立的slice,互不影响

    var a = []int{1, 2, 3}fmt.Printf("slice a : %v\n", a)var b = []int{4, 5, 6}fmt.Printf("slice b : %v\n", b)c := append(a, b...)fmt.Printf("slice c  : %v\n", c)b = append(b, 7)fmt.Printf("slice b  after apend 7: %v\n", b)a = append(a, 7)fmt.Printf("slice a  after apend 7: %v\n", a)fmt.Printf("slice c : %v\n", c)c = append(c, 7)fmt.Printf("slice c  after apend 7: %v\n", c)

打印结果:

slice a : [1 2 3]
slice b : [4 5 6]
slice c  : [1 2 3 4 5 6]
slice b  after apend 7: [4 5 6 7]
slice a  after apend 7: [1 2 3 7]
slice c : [1 2 3 4 5 6]
slice c  after apend 7: [1 2 3 4 5 6 7]

其中b...是使用...展开运算符将slice展开作为单独元素传递给函数使用

以上apend操作是在末尾添加,还可以在头部添加

s := []int{2, 3, 4, 5, 6, 7}s = append([]int{1}, s...)fmt.Println("s是:", s)s = append([]int{-1, -2}, s...)fmt.Println("s是:", s)

s是: [1 2 3 4 5 6 7]
s是: [-1 -2 1 2 3 4 5 6 7] 

2,切片copy

copy(dst,src)将src内容复制给dst切片

src := []int{1, 2, 3}dst := make([]int, 3)copy(dst, src) // 现在dst是[1, 2, 3]的拷贝fmt.Println("dst是:", dst)

copy复制后两个切片是独立的

src := []int{1, 2, 3}dst := make([]int, 3)copy(dst, src) // 现在dst是[1, 2, 3]的拷贝fmt.Println("dst是:", dst)dst = append(dst, 4)fmt.Println("dst是:", dst)fmt.Println("src是:", src)

 dst是: [1 2 3]
dst是: [1 2 3 4]
src是: [1 2 3]

copy与append实现高效 添加元素

a = append(a, 0)     // 切片扩展 1 个空间copy(a[i+1:], a[i:]) // a[i:] 向后移动 1 个位置a[i] = x             // 设置新添加的元素

具体实现:

a := []int{1, 2, 3, 4, 5, 6, 7, 8}a = append(a, 0)     // 切片扩展 1 个空间copy(a[4+1:], a[4:]) // a[i:] 向后移动 1 个位置a[4] = 88            // 设置新添加的元素fmt.Println("a是:", a)

打印:

a是: [1 2 3 4 88 5 6 7 8] 

3,切片删除 

从末尾删除

slice5 := []int{1, 2, 3, 4, 5, 6, 7, 8}new_slice5 := slice5[:len(slice5)-1]fmt.Println("new_slice5:", new_slice5)new_slice5 = slice5[:len(slice5)-5]fmt.Println("new_slice5:", new_slice5)

new_slice5: [1 2 3 4 5 6 7]
new_slice5: [1 2 3]

从头部删除 

    slice5 = slice5[1:]  //删除头部第1个元素

    slice5 = slice[5:]   //删除头部第N个元素

使用append删除

append删除元素非常灵活,可以删除头部,中间,尾部元素。注意若是希望地址不变,需要将append的结果赋值回去

 删除头部元素

slice5 = append(slice5[:0], slice5[3:]...) //删除头部元素fmt.Println("slice5:", slice5)

slice5: [4 5 6 7 8]

删除中间元素

	slice5 = append(slice5[:3], slice5[5:]...) //删除中间两个元素fmt.Println("slice5:", slice5)

slice5: [1 2 3 6 7 8]

删除尾部元素

slice5 = append(slice5[:0], slice5[0:len(slice5)-3]...) //删除尾部元素fmt.Println("slice5:", slice5)

slice5: [1 2 3 4 5] 

以上便是对slice的学习总结,若是不当之处,烦请指出。后面有新的学习领悟,会继续添加。 

这篇关于go 切片slice学习总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121992

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter