当前位置:   article > 正文

【go基础】切片

【go基础】切片

go语言中数组的长度是固定的,如果数组中元素个数已经等于数组容量时,就不能再继续往数组中添加新元素了。为了解决此问题,就有了切片(slice)类型,它是在数组的基础上重新进行了一层封装。

一、定义

切片的本质

切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。
在这里插入图片描述

基本定义

语法:var 变量 [] 类型
表面上看,定义切片和定义数组是非常相似的,就是不用写明存储元素的个数即可。

```go
package main

import "fmt"

//切片的基本操作
func main() {
	//基本定义
	var a []int                               //声明一个整型切片
	var b = []string{"liyifeng", "zhuyilong"} //声明一个string型切片并初始化
	var c = []bool{true, false}               //声明一个bool型切片并初始化

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

注意:切片是引用类型数据,必须要初始化才能使用,否则会报索引越界的错
在这里插入图片描述

基于数组定义

通过切片表达式(a[start:end]),可以将一个数组类型转换为切片类型。注意:切片表达式的起止坐标不支持负数

package main

import "fmt"

//切片的基本操作
func main() {
	//基本定义
	var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
	b := a[:]                     //拷贝整个数组 [1 2 3 4 5]
	c := a[:3]                    //左闭右开的区间,结果[1 2 3]
	d := a[3:]                    //左闭右开的区间,结果[4 5]

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述

从切片再次切片

和上面的例子类似

package main

import "fmt"

//切片的基本操作
func main() {
	//基本定义
	var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
	b := a[:]                     //拷贝整个数组 [1 2 3 4 5]
	c := b[:3]                    //左闭右开的区间,结果[1 2 3]
	d := c[3:]                    //左闭右开的区间,结果[]

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

make函数构造切片

make函数第2个参数表示长度,第3个参数表示容量,make容量不指定时,和长度保持一致。

func make(t Type, size …IntegerType) Type

基本初始化时提到过,切片没有初始化直接使用会提示索引越界的错误。一般会通过make函数对切片初始化为指定类型的空值。

package main

import "fmt"

//切片的基本操作
func main() {
	//通过make函数初始化
	//1.指定长度和容量
	var a = make([]string, 2, 10)
	fmt.Printf("%#v  长度:%d   容量:%d\n", a, len(a), cap(a))

	//2.只指定长度,默认容量和长度一致
	var b = make([]string, 2)
	fmt.Printf("%#v  长度:%d   容量:%d\n", b, len(b), cap(b))

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

二、查

len/cap:查看切片的长度和容量

通过数组初始化切片时,切片的容量是从切片表达式start开始,到整个数组结束所有的数据大小。切片相当于对原始数组指定部分的一个别名而已,指向的还是相同的空间。

package main

import "fmt"

//切片的基本操作
func main() {
	var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
	b := a[:]                     //拷贝整个数组 [1 2 3 4 5]
	c := a[:3]                    //左闭右开的区间,结果[1 2 3]
	d := a[3:]                    //左闭右开的区间,结果[4 5]

	fmt.Printf("%#v  长度:%d   容量:%d\n", a, len(a), cap(a))
	fmt.Printf("%#v  长度:%d   容量:%d\n", b, len(b), cap(b))
	fmt.Printf("%#v  长度:%d   容量:%d\n", c, len(c), cap(c))
	fmt.Printf("%#v  长度:%d   容量:%d\n", d, len(d), cap(d))

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

基于下标的遍历

package main

import "fmt"

//切片的基本操作
func main() {
	var a = []int{1, 2, 3, 4, 5} //声明并初始化一个整型切片
	for i := 0; i < len(a); i++ {
		fmt.Println(a[i])
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述

for range遍历

package main

import "fmt"

//切片的基本操作
func main() {
	var a = []int{1, 2, 3, 4, 5} //声明并初始化一个整型切片
	for idx, value := range a {
		fmt.Printf("[idx]:%d  [val]:%v\n", idx, value)
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

判断切片是否为空

要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。切片是引用类型,不支持直接比较,只能和nil比较。
在这里插入图片描述

三、增

通过内置的append函数实现切片元素的增加,如果超过切片的容量会自动扩容,其实也就是重新定义开辟了一块新的地址空间存放这些数据。所以append函数是有返回值的,需要用一个变量来接收。

  • 添加1个元素
package main

import "fmt"

//切片的基本操作
func main() {
	var a = make([]int, 1) //声明一个整型切片
	for i := 0; i < 10; i++ {
		a = append(a, i)
		fmt.Printf("%#v  [len]:%d    [cap]:%d\n", a, len(a), cap(a))
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片
可以看到,append动态扩容的效果i,当长度在某个范围内,容量是按照当前容量的2倍进行扩容。

  • 添加多个元素
package main

import "fmt"

//切片的基本操作
func main() {
	var a = make([]int, 1) //声明并初始化一个整型切片
	a = append(a, 1, 2, 3, 4, 5)
	fmt.Printf("%#v  [len]:%d    [cap]:%d\n", a, len(a), cap(a))

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
注意:因为切片定义的时候已经对第1个元素进行了零值初始化了,所以第1个元素是0。

  • 添加切片,使用…
package main

import "fmt"

//切片的基本操作
func main() {
	var a = make([]int, 1)         //声明并初始化一个整型切片
	var b = []int{-10, -9, -8, -7} //声明并初始化一个整型切片
	a = append(a, b...)
	fmt.Printf("%#v  [len]:%d    [cap]:%d\n", a, len(a), cap(a))

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

四、改

和数组操作一致,按照下标即可修改切片内指定元素。注意:通过数组初始化的切片,修改了元素内容,本质上是对数组内容进行的修改【前提:没有动态扩容,否则切片指向的就是一个新地址了】

package main

import "fmt"

//切片的基本操作
func main() {
	//基本定义
	var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
	b := a[:]                     //拷贝整个数组 [1 2 3 4 5]
	c := a[:3]                    //左闭右开的区间,结果[1 2 3]
	d := a[3:]                    //左闭右开的区间,结果[4 5]
	e := a[1:4]                   

	c[2] = 1000
	// e = append(e, 3000, 4000, 5000, 6000) //即使append操作,超过原有容量时,数组的值不会被修改
	e = append(e, 3000) //即使append操作,不超过原有容量时,指向的还是原来数组的地址,所以数组的值也会被修改
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)
	fmt.Println(e)

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在这里插入图片描述
如果执行的是屏蔽的append语句,可以看到完全不同的效果。

五、删

没有直接提供删除的函数,可以借助append函数实现。格式为:
a := append(a[:index], a[index+1:]…)

package main

import "fmt"

//切片的基本操作
func main() {
	var a = []int{1, 2, 3, 4, 5, 6, 7, 8, 9} //声明并初始化一个整型切片
	//删除4,5,6
	b := append(a[:3], a[6:]...)
	fmt.Printf("%#v  [len]:%d    [cap]:%d\n", b, len(b), cap(b))

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

copy:切片复制

由于切片是引用类型,指向了同一块内存地址。修改b的同时a的值也会发生变化。如果想完全复制一份的话就可以使用内置的copy函数,可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的定义如下:

copy(destSlice, srcSlice []T)

package main

import "fmt"

//切片的基本操作
func main() {
	var a = []int{1, 2, 3, 4, 5, 6, 7, 8, 9} //声明并初始化一个整型切片
	var c = make([]int, 3)
	b := a[:2]

	copy(c, b)
	fmt.Println("//*******修改前:")
	fmt.Printf("%#v\n", a)
	fmt.Printf("%#v\n", b)
	fmt.Printf("%#v\n", c)

	fmt.Println("//*******修改后:")
	b[1] = 1000
	fmt.Printf("%#v\n", a)
	fmt.Printf("%#v\n", b)
	fmt.Printf("%#v\n", c)

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

参考链接:https://www.liwenzhou.com/posts/Go/06_slice/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/206329
推荐阅读
相关标签
  

闽ICP备14008679号