切片注意事项和细节(2) | 学习笔记

简介: 简介:快速学习切片注意事项和细节(2)

开发者学堂课程【Go 语言核心编程 - 基础语法、数组、切片、Map :切片注意事项和细节(2)】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/625/detail/9641


切片注意事项和细节(2)

 

内容介绍:

一、切片注意事项和细节

二、使用 append 函数进行动态追加的介绍和案例

三、切片的拷贝操作

 

一、切片注意事项和细节

1.切片注意事项和细节说明:

(1) 切片初始化时 var slice = arr[startIndex:endIndex]

说明:从arr数组下标为 startlndex,取到下标为 endIndex的元素(不含arr[endIndex])。

(2) 切片初始化时,仍然不能越界。范围在[0-len(arr)]之间,但是

以动态增长。

//切片重要特性:动态增长

var slice = arr[0:end]可以简写var slice = arr[:end]

var slice = arr[start:len(arr)]可以简写:var slice = arr[start:]

var slice = arr[0:len(arr)]可以简写:var slice = arr[:]

(3) cap 是一个内置函数,用于统计切片的容量,即最大可以存放

少个元素。

(4) 切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者 make 一个空间供切片来使用

(5) 切片可以继续切片

 

二、使用 append 函数进行动态追加的介绍和案例

用 append 内置函数,可以对切片进行动态追加

1.代码:

var arr [5] int = [5]int {1,2,3,4,5}

var slice = arr [:]

//追加具体的元素

slice = append(slice,10,20,30)

fmt.Println(“slice=”,slice)

//在切片上追加切片

var a = []int{100,200}

slice = append(slice,a…)

fmt.Println(“slice=”,slice)

//当切片数据不够用时,可以进行动态增长,使用的内置函数就是append

2.打开网页,查看 append 函数的作用:

内建函数 append 将元素追加到切片的末尾。若它有足够的容量,其目标就会重新切片以容纳新的元素。否则,就会分配一个新的基本数组。append 返回更新后的切片,因此必须存储追加后的结果。

//append 可以用来扩容

3.切片 append 操作的底层原理分析:

(1) 切片 append 操作的本质就是对数组扩容

(2) go 底层会创建一下新的数组 newArr(装扩容后大小)  //在做 append 底层的时候会创建一个新的数组,将新的数组扩容之后,然后在重新赋给新的切片

(3) 将 slice 原来包含的元素拷贝到新的数组 newArr  //将准备追加的新的切片数组先拷贝到新的数组中

(4) slice 重新引用到 newArr

(5) 注意newArr 是在底层来维护的,程序员不可见 //slice在底层如何扩容或者创建新的数组,程序员无需关心

(6) 案例演示说明

append 底层原理分析图:

//进行切片时,slice3会引用到新的数组,当执行到 append 时,内存中会先创建一个数组,但是数组是在底层中所创建的我们无法观察。数组在创建过程中,由于会追加三个元素,所以底层会进行扩容。在默认情况下,其实刚生成的数组中的元素的值应该为0。再创建新的数组过程中,是不可能在原先的数组里进行元素追加的,所以要把元素{100,200,300}拷贝至新的数组中,然后新追加的元素会继续赋值到新的数组中,新的数组就形成了,这时,slice3的指针会指向新的数组,而之前的数组就消失了。

image.png

由于下方的空间没有被变量引用,所以它将变成垃圾,被系统回收,最终呈如下效果:

image.png

假设是追加的 slice4,那么就会创建一个新的 slice4,让其指向新的空间,原先的slice3 仍然没有变化

image.png

案例:

var slices3 []int =[]int{100,200,300}  //定义一个切片

fmt.Println(“slice3”,slice)  //将切片进行输出

运行结果:slice3 [100 200 300 ]

(7) 如果要在后方追加新的元素:

第一种方式:

//通过 append 直接给 slice3 追加具体的元素(此元素的值要和上方的数据类型类型保持一致)

slice3 = append(slice3,400,500,600)  //追加新的元素

//注意:在追加元素完成后,slice3本身没有变化,在追加的过程中,实际上是内部上进行的分配操作,创建了一个新的数组来进行追加的操作,其实返回的是新的追加完成后的数组,因此需要接收,否则 slice3 还是没有变化。

fmt.Println(“slice3”,slice3)  //输出slice3

假设使用 slice4 来进行接收:
fmt.Println(“slice4”,slice4)  //slice4是追加过后的元素 {100,200,300400,500,600}

fmt.Println(“slice3”,slice3)  //slice3仍然是之前的元素 {100,200,300}

//实际 slice3 本身没有变化,只是将追加过后的东西重新返回一个结果给新的变量slice4

运行结果如下:

image.png

可以发现 slice3 没有发生变化,slice4 发生了变化

需要的效果其实就是改变 slice3,一般情况下只需要将新的变量值重新赋给 slice3 即可:
slice3 = append(slice3,400,500,600)

fmt.Println(“slice3”,slice3)

//slice3真正意义上实现了扩容

运行结果如下:

image.png

slice3 已经是最新的数据

第二种方式:

//在 append 后直接追加一个切片
slice3 = append(slice3,slice3…)  //通过 append 函数将切片 slice3 追加给slice3,自我增长

//后面部分的 slice3 也可以是其他的切片,而且此部分必须是切片,不能是数组

//…是规定的写法,必须写上

//{100,200,300,400,500,600, 100,200,300,400,500,600}

fmt.Println(“slice3”,slice3)  //重新增加切片后进行输出

运行结果如下:

image.png

slice3 在自己的基础上追加了一份slice3

 

三、切片的拷贝操作

1.切片使用 copy 内置函数完成拷贝

举例说明:

func main() {

var a []int = []int {1,2,3,4,5}  //切片,是单独拥有一个空间

var slice = make([]int , 10)  //make了一个切片,大小为10,在没有赋予值的时候,默认的值都是0

//slice 也有一个独立的空间

fmt.Println(slice)  //在没有赋值的情况下,打印出10个0

copy(slice,a)  //将a的数据拷贝给 slice,将1,2,3,4,5分别拷贝到对应的位置,后面的值保留原来的值为0

fmt.Println(slice)

}

说明:copy(para1, para2):para1 和 para2 都是切片类型

//注意:拷贝操作必须要求全是切片类型才可以执行拷贝

2.案例:

var slice4 []int = []int{1,2,3,4,5}  //新建一个数组

var slice5 = make([]int,10)  //使用make的方式新建一个切片

copy(slice5,slice4)  //将slice4拷贝至slice5

fmt.Println(“slice4”,slice4)  //输出1,2,3,4,5

fmt.Println(“slice5”,slice5)  //输出1,2,3,4,5,0,0,0,0,0

}

运行效果如下:

image.png

slice4 与slice5 都是独立的空间

3. 问题:如果修改slice4会对slice5造成影响吗?

答:不会有影响,因为他们的空间都是独立的,他们之间的数据也是独立的。

4.对代码的说明:

(1) copy(para1, para2)参数的数据类型是切片

(2) 按照上面的代码来看, slice4 和 slice5的数据空间是独立,相互不影响,也就是说 slice4[0]= 999,slice5[0]仍然是1

相关文章
|
6月前
第六章 利用数组处理批量数据
第六章 利用数组处理批量数据
29 0
|
程序员 Go 开发者
使用切片的区别分析|学习笔记
快速学习使用切片的区别分析。
112 0
使用切片的区别分析|学习笔记
|
编译器 Scala 开发者
函数使用注意事项和细节2|学习笔记
快速学习函数使用注意事项和细节2。
|
Go 开发者
切片注意事项和细节(1) | 学习笔记
简介:快速学习切片注意事项和细节(1)
124 0
切片注意事项和细节(1) | 学习笔记
|
Go vr&ar 开发者
切片注意事项和细节(3) | 学习笔记
简介:快速学习切片注意事项和细节(3)
切片注意事项和细节(3) | 学习笔记
|
Go vr&ar 开发者
数组注意事项和细节(2)|学习笔记
快速学习数组注意事项和细节(2)。
130 0
数组注意事项和细节(2)|学习笔记
|
程序员 Go 开发者
使用切片的三种方式|学习笔记
快速学习使用切片的三种方式。
168 0
使用切片的三种方式|学习笔记
|
网络协议 程序员 测试技术
管道的注意事项和细节(2)|学习笔记
快速学习管道的注意事项和细节(2),使用 select 可以解决从管道取数据的阻塞问题【案例演示】 我们在管道读取数据的时候要 close 管道,如果没有关闭,这个时候他会阻塞,而且会发生死锁,但有些情况如想在不想关闭的情况下也不被阻塞的话,我们就要使用 select
管道的注意事项和细节(2)|学习笔记
|
Java 编译器 Scala
函数使用注意事项和细节3|学习笔记
快速学习函数使用注意事项和细节3。
|
Java 编译器 Scala
函数使用注意事项和细节1|学习笔记
快速学习函数使用注意事项和细节1。