我又写“bug”了,关于go切片的探究

简介: 我又写“bug”了,关于go切片的探究

将问题抽象出来


最近在用go写定时任务的时候,采取了切片的方式作为数据的存储载体。但是在编写的过程中遇到了一个"bug",我们将问题抽象一下,以便更快的找到问题。


我们的需求

已有切片的数据:

image.png


我们想要插入一个数据6,将其放置到57之间。

image.png

最后得到的切片是

image.png


如上简单的需求,我们很快变便写好了代码,代码如下:

s1 := []int{1,3,5,7,9}
newVal := 6
k := 3
temp := s1[k:]
s1 = append(s1[:k],newVal)
s1 = append(s1,temp...)



如上代码,我们先申请一个切片,数据为: 1 3 5 7 9 , 而后我们定义新的变量newVal6


此时我们想实现插入的动作,具体如何操作呢,我们操作步骤如下:

temp := s1[k:]我们将数组以k切割出来,k3,即将7,9抓出来,存入到变量temp中,


image.png


而后使用append串起来,理想状态是这样的。

image.png

看代码,也和我们想象的一样,我们最后添加一个打印s1切片的语句,并且我们运行下代码尝试一下。

image.png



探寻底层原理


上面的代码执行后结果肯定不符合我们预期,应该是我们基础不牢固导致的,看来我们得有必要学习一下切片的基础知识了。


所谓的切片,也称之为可变长的数组,由三个属性构成: 起始地址、长度 和 容量。


其中go给我们提供了一下几种方法来获取长度和容量的。


len: 获取有效长度。

cap: 获取容量。

我们来看下,我们如上代码的长度和容量分别是多少。

s1 := []int{1,3,5,7,9}
fmt.Println("长度为:",len(s1),"容量为:",cap(s1))

我们执行下

image.png


我们画一下关系图

image.png


我们发现,容量和长度都是5,也就意味着,我们只需要append一个数据,底层数组就可以重新申请。

我们来尝试下

s1 := []int{1,3,5,7,9}
fmt.Printf("扩容前 数组地址为: %p 长度为: %d 容量为 %d\n",s1,len(s1),cap(s1))
s1 = append(s1,10)
fmt.Printf("扩容后 数组地址为: %p 长度为: %d 容量为 %d\n",s1,len(s1),cap(s1))


image.png

有了如上关于切片的基础知识,我们来推理一下我们为什么会引发问题呢?

我们将代码贴图在此处,便于我们分析。

image.png

首先,我们创建了一个数组 ,其值为: 1 3 5 7 9

image.png


接着我们temp映射在了s1[3:]处,此处要记住数组下标哦。用图示如下:

image.png

而后我们新增了数据6,图示如下

image.png


最后,我们再将temp的值追加到s1之后。


那么,请问此时temp79 还是 69呢?


由于是对数组的引用,所以它会取s1[3]s1[4],故值为69,我们追加后,最后的结果是图示如下:

image.png


这就是最后的结果。



尝试解法


我们已经复习了go切片的相关知识,那么这个问题修改起来应该得心应手才对,我们来尝试下呢。

我们知道,在同一个数组下,我们想完成这个功能,还是稍微有点复杂的。所以我们就完完全全申请一个新的底层数组好了呀,我们可以这样写:

s1 := []int{1,3,5,7,9}
newVal := 6
k := 3
// 定义了一个新的切片
var temp []int
temp = append(temp,s1[k:]...) // 将数据放入新的切片中
s1 = append(s1[:k],newVal)
s1 = append(s1,temp...)
fmt.Println(s1)


如上代码,我们执行一下,查看结果

image.png


功能已经实现了,非常赞。




总结


有句老话说得好,基础不牢,地动山摇。我们之所以出现了该问题,是我们以为我们定义了一个切片,就能完成“独自占有”数组,殊不知我们得到的还是原有数组的引用,这本来是基础知识,哎,栽倒坑里了,正所谓,温度而知新,还是要把基础打牢固,多拿出来学习才行,怎么样,切片好玩吧,快来尝试一下吧。







相关文章
|
19天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
31 7
|
29天前
|
Go 索引
Go语言中,遍历数组或切片
在Go语言中,遍历数组或切片
43 6
|
21天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
91 62
|
25天前
|
Go 索引
go语言遍历数组和切片
go语言遍历数组和切片
20 2
|
1月前
|
存储 Go
|
1月前
|
Java Go 数据处理
go语言使用切片而非数组
【10月更文挑战第18天】
16 1
|
1月前
|
Go
|
2月前
|
存储 安全 Go
Go语言切片:从入门到精通的深度探索###
本文深入浅出地剖析了Go语言中切片(Slice)这一核心概念,从其定义、内部结构、基本操作到高级特性与最佳实践,为读者提供了一个全面而深入的理解。通过对比数组,揭示切片的灵活性与高效性,并探讨其在并发编程中的应用优势。本文旨在帮助开发者更好地掌握切片,提升Go语言编程技能。 ###
|
3月前
|
Go 索引
Go to Learn Go之切片
Go to Learn Go之切片
35 1
|
3月前
|
编译器 Go 索引
Go数组、多维数组和切片(动态数组),及常用函数len(),cap(),copy(),append()在切片中的使用
本文介绍了Go语言中数组、多维数组和切片(动态数组)的基本概念和操作,包括数组的定义、初始化、访问,多维数组的定义和访问,以及切片的创建、使用和扩容。同时,还讲解了切片中常用的函数len()、cap()、copy()和append()的使用方法。