玩转Go语言之切片

177 阅读4分钟

1.无论是C语言中的数组还是Go语言中的数组,数组的长度一旦确定就不能改变, 但在实际开发中我们可能事先不能确定数组的长度, 为了解决这类问题Go语言中推出了一种新的数据类型切片

2.什么是切片?

切片简单理解就是一个可变长度的数组

底层的实现原理就是一个结构体, 结构体中有一个指针指向了一个数组

本质上所有的数据都是保存在指向的数组中的

type slice struct{
           array unsafe.Pointer // 指向底层数组指针

           len int // 切片长度(保存了多少个元素)

           cap int // 切片容量(可以保存多少个元素)

}

3.如何创建切片

1.通过数组来创建切片
3.1通过数组来创建格式: [起始位置:结束位置], 从起始位置开始截取, 直到结束位置, 但是不包括结束位置注意:  截取了多少个元素, len就等于几容量等于数组的长度 - 起始位置       var ages [5]int = [5]int{1, 3, 5, 7, 9}
	// 2.通过数组创建切片
	// [起始位置:结束位置], 从起始位置开始截取, 直到结束位置, 但是不包括结束位置
	//var sce []int = ages[0:2]
	//var sce []int = ages[2:4]
	// 注意点: 如果只写了起始位置, 没有写结束位置, 那么会截取到最后
	//var sce []int = ages[0:]
	//var sce []int = ages[2:]
	// 注意点: 如果只写了结束位置, 没有写开始位置, 那么会从开始截取到指定的结束位置
	//var sce []int = ages[:2]
	// 注意点: 如果只写了:, 那么就是从开始截取到末尾
	var sce []int = ages[:]
	fmt.Println(sce)
	// 计算切片当前保存数据的个数
	fmt.Println(len(sce))
	// 计算切片总共可以保存数据的个数
	fmt.Println(cap(sce))2.通过make函数来创建切片
       // 第一个参数: 告诉系统要存储什么类型的数据
	// 注意点: 如果是创建切片一定要在传入的数据类型前面写上[]
	// 第二个参数: 告诉系统创建出来的切片len等于多少
	// 第三个参数: 告诉系统创建出来的切片cap等于多少
	// 注意点: 第三个参数可以省略, 如果省略切片的容量就等于切片的长度(等于第二个参数)
	//var sce []int = make([]int, 2, 5)
	var sce []int = make([]int, 2)
	fmt.Println(sce)
	fmt.Println(len(sce))
	fmt.Println(cap(sce))3.通过语法糖来创建切片
	// 一定要注意[]里面没有值就是切片
	// 通过Go提供的语法糖来创建len等于cap
	var sce []int = []int{1, 3, 5} // 相当于make([]int, 3)
	fmt.Println(sce)
	fmt.Println(len(sce))
	fmt.Println(cap(sce))

append函数

1.容量

如果通过append函数追加数据之后超过了原有的容量, 那么系统内部会自动按照当前容量*2的方式重新定义一个数组作为切片保存数据的模型

注意点: 

容量小于1024的时候扩容, 会按照原有容量的2倍扩容

容量大于1024的时候扩容, 会按照原有容量1/4倍扩容


2.为什么append函数要返回一个切片

因为在扩容的时候会重新定义一个新的切片, 所以需要返回一个切片

var sce []int = make([]int, 2, 5)
sce = append(sce, 6)	
fmt.Printf("%p\n", sce)	
fmt.Println(sce)	
fmt.Println(cap(sce))

切片的使用

删除切片中的值

var sce []int = {1,3,5,7,9}
index := 2
sce = Append(sce[:index],sce[index+1:]...)

规律:

将第二次截取的切片添加到第一次截取的截屏后面即可

// 通过切片生成切片的注意点	

// 1.创建一个数组	var 
arr [5]int = [5]int{1, 3, 5, 7, 9} // 数组	
// Go语言中不能直接通过数组名获取数组的地址	
//fmt.Printf("%p\n", arr)	
fmt.Printf("%p\n", &arr)	
fmt.Printf("%p\n", &arr[0])	

// 2.通过数组创建一个切片	
var sce []int = arr[:]	
// 直接打印sce打印的是sce中指针保存的地址	
// 也就是底层指向的那个数组的地址	
fmt.Printf("%p\n", sce)

// 3.通过切片创建一个切片	
// 通过切片创建一个切片, 新的切片和老的切片底层指向同一个数组	
var sce2 []int = sce[:]	fmt.Printf("%p\n", sce2)	

// 4.直接修改数组的值	
//arr[1] = 666	
//sce[1] = 666	
sce2[1] = 666	
fmt.Println(arr)	
fmt.Println(sce)	
fmt.Println(sce2)

copy的使用
sce1 := []int{1, 3} // 源切片	
sce2 := []int{0, 0, 0} // 目标切片	
fmt.Println(sce2)	
// 第一个参数:目标切片	
// 第二个参数:源切片	
// 会将源切片中的数据拷贝到目标切片中	
// 拷贝的时候会以目标切片为主	
copy(sce2, sce1)	
fmt.Println(sce2)//{1,3,0}

通过copy改变字符串中的字符
var str string = "www.it666.com"	
sce := make([]byte, len(str))	
copy(sce, str)	
sce[0] ='M'	
fmt.Printf("%s\n", sce)