Golang 中的切片

数组切片

上一篇我已经提过数组的特点:即数组的长度在定义之后无法修改;数组是值类型,无法满足我们需要引用传递.
Go 语言提供了切片来弥补数组的不足!
从底层的实现角度来看,数组实际上仍然使用数组来管理元素,基于数组切片添加了一系列的管理功能,可以随时动态扩充存放空间,并且可以随意传递而不会导致管理的元素被重复复制.

1:创建数组切片
	func main(){
		//定义数组
		var array [5]int = [5]int{3,4,6,8,88}
		//基于定义的数组创建切片
		var mySlice []int = array[:2]
		fmt.Println("Print elemetes of array")
		for _, v := range array {
			fmt.Print(v)
		}
		fmt.Println("\nPrint elemetes of mySlice")
		for _, v := range mySlice {
			fmt.Print(v)
		}
	}

运行结果:

Print elemetes of array
346888
Print elemetes of mySlice
34

大家应该已经注意到了,go 语言支持类似 array[first:last],这样的方式来基于数组生成一个数组切片,而且用法比较灵活,以下方式都支持创建数组切片:

	//基于Array的所有元素创建数组切片:
	mySlice = Array[:] 
	//基于Array的前五个元素创建数组切片:
	mySlice = myArray[:5]
	//从Array第五元素开始创建所有的元素切片
	mySlice = myArray[5:]
2:直接创建切片

并非事先准备一个数组才能创建数组切片,go语言提供的内置函数 make() 可以用户灵活地创建数组切片.
列如:

//创建一个初始元素个数为5的数组切片,元素初始化值为0:
mySlicel := male([]int, 5)
//创建一个初始化元素个数为5的数组切片,元素初始化值为0,并且预留10个元素的存贮位置
mySlicel := make([]int, 5, 10)
//直接创建并且初始化元素个数为4
mySlicel :=[]int{1,2,3,4,5}

元素遍历:

//操作数组元素的所有方法也都适用于切片如:
	func slicel(){
		mySlicel :=[]string{"zhangsan","lisi","wanger"}
		
		for i := 0; i < len(mySlicel); i++ {
			fmt.Println("MySelicel", i ,"=",mySlicel[i])
		}
	
		fmt.Println("********************************")

		for i, v := range mySlicel {
			fmt.Println("MySelicel", i ,"=",v)
		}

	}

对比上面两种便利方式,推荐使用 range 更简单易懂

3:动态增减元素

可动态增减元素是数组切片比数组更为强大的功能,与数组相比,数组切片多了一个存储能力(capacity)的概念,即元素个数和分配空间可以使两个不同的值,合理设置存储能力的值,可以大幅降低数组切片内部重新分配内存和搬运内存块的频率,从而大大提高程序性能.
假如你明确知道当前创建的数组切片最多可能需要存储的元素个数为50,那么如果你设置的存储能力小于50,比如20,那么在元素超过20时,底层将会发生至少一次这样的动作——重新分配一块“够大”的内存,并且需要把内容从原来的内存块复制到新分配的内存块,这会产生比较明显的开销。给“够大”这两个字加上引号的原因是系统并不知道多大才是够大,所以只是一个简单的猜测。比如,将原有的内存空间扩大两倍,但两倍并不一定够,所以之前提到的内存重新分配和内容复制的过程很有可能发生多次,从而明显降低系统的整体性能。但如果你知道最大是50并且一开始就设置存储能力为50,那么之后就不会发生这样非常耗费CPU的动作,达到空间交换时间的效果.

go语言提供了 cap()函数和 len()函数前者用来返回数组切片分配的空间大小,后者返回的是数组切片中当前所存储的元素个数.

	func main() {
	
		mySelice := make([]int, 5, 10)

		fmt.Println("len(mySelice)", len(mySelice))
		fmt.Println("cap(mySelice)", cap(mySelice))
	}

输出结果

len(mySelice) 5
cap(mySelice) 10	

上述 mySelice 的例子可以看出已包含5个元素后面继续新增元素,可以使用 append() 函数
下面代码可以从尾端给 mySelice 加上3个元素,从而生成一个新的数组切片:

	mySlice = append(mySlice, 1, 2, 3)

函数 append() 的第二个参数其实是一个不定参数,我们可以按照自己的需求添加若干个元素,甚至直接将一个数组切片追加到另一个数组的末尾:

	mySlice2 :=  []int{8, 9, 10}
	mySlice = append(mySlice, mySlice2...)

这里需要注意,我们在第二个参数 mySlice2 后面加了三个点,即一个省略号,如果没有这个省略号的话,会有编译错误,以为按照 append() 的语义,从第二个参数起的所有参数都是待附加的元素. 因为 mySlice 中的元素类型为 int,所以直接传递 mySlice2 是行不通的,加上省略号相当于把 mySelice 包含的所有元素打散后传入.
也就是说,上述代码相当于:::

	mySlice = append(mySlice, 8, 9, 10)

数组切片会自动处理存储空间不足的问题,如果追加的内容长度超过当前已分配的存储空间即 cap() 返回的信息,数组切片会自动分配一块足够大的内存

4:基于数组切片创建数组切片

类似于数组切片可以基于一个数组创建,数组切片也可以基于另一个数组切片创建,下面的例子基于一个已有数组切片创建另一个数组切片:

		oldSlice := []int{1, 2, 3, 4, 5}
		newSlice := oldSlice[:2]

基于 oldlice 前两个元素创建新的切片,有意思的是,选择的 oldSlice 元素范围甚至可以超过所包含的元素个数,比如 newSlice 可以基于 oldSlice 的前6个元素创建,虽然 oldSlice只包含了5个元素,只要这个选择的范围不超过 oldSlice 的存储范围,即 cap() 返回的值,那么这个创建程序就是合法的,newSlice 中超出 oldSlice元素的部分都会填上 0

5:内容复制

数组切片支持 go 语言的另一个内置函数 copy(),用于将内容从一个数组切片复制到另一个数组切片. 如果加入的两个数组不一样大,就会按照较小的那个数组切片元素中的个数进行复制,例如:

	slice1 := []int{1, 2, 3, 4, 5} 
	slice2 := []int{5, 4, 3} 
	copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
	copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值