Go切片

栏目: IT技术 · 发布时间: 4年前

内容简介:1.起始位置:切片引用数组的开始位置。2.大小:切片中的元素个数。切片中的大小不能超过容量数量。可以使用len()函数对切片统计大小。3.容量:切片最大可存的元素个数。如果空间不足以容纳足够多的元素,切片就会进行动态“扩容”,此时新切片的长度会发生改变。一般切片的扩容是按照扩容前容量的2倍。可以使用cap()函数对切片容量进行统计。

1.起始位置:切片引用数组的开始位置。

2.大小:切片中的元素个数。切片中的大小不能超过容量数量。可以使用len()函数对切片统计大小。

3.容量:切片最大可存的元素个数。如果空间不足以容纳足够多的元素,切片就会进行动态“扩容”,此时新切片的长度会发生改变。一般切片的扩容是按照扩容前容量的2倍。可以使用cap()函数对切片容量进行统计。

切片与数组的区别

1.切片是对数组中的连续引用。切片的初始位置指向数组的内存地址,如果切片的值改变,数组对应的值也会对应改变。

2.切片的长度是动态的,本质上是一个可变的动态数组。数组的长度在定义的时候就决定好了,后期是无法修改数组的长度的。

3.切片的长度是可以动态扩容的[如上面容量一次提到的]。

切片内存分布

Go切片

切片的定义

通过数组定义

array[startIndex:endIndex]

1.array:被切片定义的数组名称。

2.startIndex:切片的开始位置。

3.endIndex:切片的结束位置。结束位置不包含在内的。

array := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "G", "K", "L"}

slice := array[2:5]

从数组或切片生成新的切片拥有如下特性:

1.取出的元素数量为:结束位置 - 开始位置。

2.取出元素不包含结束位置对应的索引,切片最后一个元素使用 slice[len(slice)] 获取。

3.当缺省开始位置时,表示从连续区域开头到结束位置。

4.当缺省结束位置时,表示从开始位置到整个连续区域末尾。

5.两者同时缺省时,与切片本身等效。

6.两者同时为0时,等效于空切片,一般用于切片复位。

直接创建切片

var name []type

1.name:切片名称。

2.type:切片类型。

// 直接申明切片
var sliceName1 []string // 直接申明一个空切片

var sliceName2 = []int{} // 申明一个值为空的切片

var sliceName3 = []int{1, 2, 3} // 申明一个切片,并初始化值

if sliceName1 == nil {
	fmt.Println("sliceName1是空切片")
}

if sliceName2 == nil {
	fmt.Println("sliceName2是空切片")
}

if sliceName3 == nil {
	fmt.Println("sliceName3是空切片")
}
fmt.Println(sliceName1, sliceName2, sliceName3)
// 输出内容
sliceName1是空切片
[] [] [1 2 3]

因为sliceName2在定义时,给初始化了一个空值。虽然该切片的内容是空,但实际是分配过内存了。如下演示代码:

// 测试三个指针的内存地址
fmt.Printf("%p\t%p\t%p", sliceName1, sliceName2, sliceName3)
0x0     0x1195a98       0xc00008a020

使用make创建指针

make([]type,size,cap)

1.type 是指切片的元素类型。

2.size 指的是为这个类型分配多少个元素。

3.cap 为预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题。

使用 make() 函数生成的切片一定发生了内存分配操作,但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。

// 使用make方式创建切片
slice1 := make([]string, 2, 3)
slice1[0] = "1"
fmt.Println(slice1)

slice2 := make([]string, 2, 3)
fmt.Println(slice2)

fmt.Println("切片的长度为", len(slice1))
fmt.Println("切片的容量为", cap(slice1))
// 输出结果
[1 ]
[ ]
切片的长度为 2
切片的容量为 3

当切片未给对应的下标赋值时,会根据定义的切片类型初始化一个值。

切片的迭代

切片从本质上来讲,是一个动态的数组,因此可以直接使用for循环进行迭代即可。

// 使用for迭代切片
slice := []int{1, 2, 3, 4}
for index, value := range slice {
	fmt.Println("切片slice的index,value分别为", index, value)
}
// 输出结果
切片slice的index,value分别为 0 1
切片slice的index,value分别为 1 2
切片slice的index,value分别为 2 3
切片slice的index,value分别为 3 4

切片与数组的区别

// 通过数组定义切片
var array1 = [3]int{1, 1, 3}
fmt.Println("数组的元素分别是:", array1)
slice1 := array1[0:2]
slice1[1] = 11111
fmt.Println("数组的元素分别是:", array1)
// 输出结果
数组的元素分别是: [1 1 3]
数组的元素分别是: [1 11111 3]

操作切片

追加切片

append(切片,追加元素)

1.尾部追加

// 1.默认是向切片的尾部追加元素
slice8 := make([]int, 2, 3)
fmt.Println("slice8:", slice8)
fmt.Println("slice8的容量是:", cap(slice8))
// 追加多个元素,手动解包
slice8 = append(slice8, 3, 4) 
fmt.Println(slice8)
// 这里需要使用...,切片需要进行解包
slice8 = append(slice8, []int{1, 2, 3, 4}...) 
fmt.Println(slice8)
// 当切片的追加容量超过初始容量,切片会自动进行扩容,扩容的以2倍增长。
fmt.Println("slice8的容量是:", cap(slice8))
slice8: [0 0]
slice8的容量是: 3
[0 0 3 4]
[0 0 3 4 1 2 3 4]
slice8的容量是: 12

2.头部添加

// 头部添加
slice8 = append(make([]int, 2, 3), slice8...)
fmt.Println("向头部追加元素", slice8)

在切片开头添加元素一般都会导致内存的重新分配,而且会导致已有元素全部被复制1次。因此,从切片的开头添加元素的性能要比从尾部追加元素的性能差很多。

// 测试向头部添加,切片内存地址变化
slice8 := make([]int, 2, 3)
fmt.Printf("切片内存地址:%p", slice8)
slice8 = append(make([]int, 1, 3), slice8...)
fmt.Println("追加切片元素", slice8)
fmt.Printf("切片内存地址:%p", slice8)
// 输出结果
切片内存地址:0xc00008a0e0
追加切片元素 [0 0 0]
切片内存地址:0xc00008a100

3.中间添加

a.每个添加操作中的第二个append调用都会创建一个临时切片,并将 a[i:] 的内容复制到新创建的切片中,然后将临时创建的切片再追加到 a[:i] 中。

b.基本公式:append(sliceName[0:x], append(要追加的切片, sliceName[x:]…)…)向x位置追加一个切片。

//向切片的中间位置添加元素
slice9 := make([]int, 3, 10)
fmt.Println("slice9", slice9)
// 在第2个位置追加一个大小为3的切片
slice9 = append(slice9[0:2], append([]int{1, 2, 3}, slice9[2:]...)...)
fmt.Println(slice9)

删除切片

Go语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素,根据要删除元素的位置有三种情况,分别是从开头位置删除、从中间位置删除和从尾部删除,其中删除切片尾部的元素速度最快。切片的删除,发生在切片内部指针的移动,切片的内存地址是不会发生变化。

1.头部删除

// 切片头部删除
slice1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
fmt.Println("slice1切片的元素分配为:", slice1)
fmt.Printf("%p\n", &slice1)
// a.直接删除
slice1 = slice1[3:len(slice1)]
fmt.Printf("%p\n", &slice1)
// b.使用copy删除
slice1 = slice1[:copy(slice1, slice1[3:])]
// c.使用append删除
slice1 = append(slice1[:0], slice1[3:]...)
fmt.Println("删除后的切片为:", slice1)
// 输出内容
slice1切片的元素分配为: [1 2 3 4 5 6 7 8 9 10 11]
0xc00000c080
0xc00000c080
删除后的切片为: [4 5 6 7 8 9 10 11]

Go切片 2.中间删除

// 中间删除切片
// a.使用append删除
slice1 = append(slice1[:3], slice1[4:]...)
// b.使用copy删除
slice1 = slice1[:3+copy(slice1[3:], slice1[4:])]
// 输出结果
slice1切片的元素分配为: [1 2 3 4 5 6 7 8 9 10 11]
0xc00000c080
删除后的切片为: [1 2 3 5 6 7 8 9 10 11]

Go切片

3.尾部删除

slice1切片的元素分配为: [1 2 3 4 5 6 7 8 9 10 11]
0xc00007c020
删除后的切片为: [1 2 3 4 5 6 7 8]
// 输出内容为
slice1切片的元素分配为: [1 2 3 4 5 6 7 8 9 10 11]
0xc00007c020
删除后的切片为: [1 2 3 4 5 6 7 8]

Go切片

通过发现,这里有一个固定的公式,这里的3可以改为N,即代表删除N个元素。上面的copy和append方式一致。

复制切片

Go切片复制可以使用内置的copy()函数将一个数组切片复制到另一个数组切片中,如果加入的两个数组切片不一样大,就会按照其中较小的那个数组切片的元素个数进行复制。

copy(desSlice, srcSlice) int

copy()函数返回的是切片复制的个数。

// 切片复制
slice10 := make([]int, 5, 10)
slice11 := []int{1, 2, 3, 4}
slice12 := slice10
num := copy(slice11, slice10)
fmt.Println("slice11", slice11)
fmt.Printf("%p,%p,%p", &slice10, &slice11, &slice12)
fmt.Println(num)

切片的引用,被引用的切片发生改变,引用的切片也会发生改变。切片的赋值,原切片发生变动,赋值的切片不会变动。

// 打印结果
slice11 [0 0 0 0]
0xc00007c180,0xc00007c1a0,0xc00007c1c04
引用切片的值 999
复制切片的值 0 999
4 5 2 3 4 slice11 [0 0 0 0]
0xc00007c200,0xc00007c220,0xc00007c2404

以上所述就是小编给大家介绍的《Go切片》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

TensorFlow:实战Google深度学习框架(第2版)

TensorFlow:实战Google深度学习框架(第2版)

顾思宇、梁博文、郑泽宇 / 电子工业出版社 / 2018-2-1 / 89

TensorFlow是谷歌2015年开源的主流深度学习框架,目前已得到广泛应用。《TensorFlow:实战Google深度学习框架(第2版)》为TensorFlow入门参考书,旨在帮助读者以快速、有效的方式上手TensorFlow和深度学习。书中省略了烦琐的数学模型推导,从实际应用问题出发,通过具体的TensorFlow示例介绍如何使用深度学习解决实际问题。书中包含深度学习的入门知识和大量实践经......一起来看看 《TensorFlow:实战Google深度学习框架(第2版)》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具