我又写“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


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




总结


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







相关文章
|
2月前
|
Go
Go 中使用切片来实现动态数组的功能
Go 中使用切片来实现动态数组的功能
|
2月前
|
存储 监控 Go
【Go语言精进之路】构建高效Go程序:了解切片实现原理并高效使用
【Go语言精进之路】构建高效Go程序:了解切片实现原理并高效使用
43 3
|
2月前
|
Go
go语言数组与切片
go语言数组与切片
30 0
|
12天前
|
Go
Go 1.21的新特性: 切片和映射
Go 1.21的新特性: 切片和映射
|
13天前
|
存储 Go
go 切片长度与容量的区别
go 切片长度与容量的区别
|
21天前
|
存储 Go
go切片和指针切片
go切片和指针切片
13 2
|
4天前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
|
1月前
|
编译器 Go
Go中遇到的bug
【7月更文挑战第4天】
35 7
|
5天前
|
人工智能 Go
go切片参数传递用值还是指针
go切片参数传递用值还是指针
10 0
|
12天前
|
存储 Go 开发者
在Go中对切片/数组求和的多种方法
在Go中对切片/数组求和的多种方法