Go切片

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

内容简介: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切片》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Game Programming Patterns

Game Programming Patterns

Robert Nystrom / Genever Benning / 2014-11-2 / USD 39.95

The biggest challenge facing many game programmers is completing their game. Most game projects fizzle out, overwhelmed by the complexity of their own code. Game Programming Patterns tackles that exac......一起来看看 《Game Programming Patterns》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具