清水泥沙

golang基础(14.数组切片)

数组定义长度后是无法修改的,数组的长度是数组类型本身的一部分,长度是数组内的一个内置常量,因此我们不能对数组进行一个增删操作。显然数组这种不灵活的特性是不能满足日常开发需求的,因此golang提供了另一种数据类型(slice)数组切片来你补数组的不足。数组切片是一个能对元素进行增删的数组,它的底层就是基于数组实现的。

数组切片的定义

在go中,定义数组切片稍微与定义数组不同,数组是需要指定长度和类型的,数组切片只需要指定类型不需要指定长度。

package main

import "fmt"

func main() {
	// 数组
	var arr = [5]int{1, 2, 3, 4, 5}

	// 切片
	var _slice = []int{1, 2, 3, 4, 5}

	fmt.Println(arr)
	fmt.Println(_slice)
}
切片是一个可变长度同一类型元素的集合,切片的长度可以随着元素增长而增长(不会因为减少而减少),不过数组底层管理依然使用数组来管理元素。切片是数组的一层封装,基于数组为其提供一系列管理功能,可以动态拓展存储空间。

创建数组切片

创建数组切片的方法主要有三种 —— 基于数组基于数组切片直接创建

基于数组

数组切片可以基于一个已经存在的数组创建。数组可以看做是切片的底层数组,切片则是其某个连续片段的引用。切片可以局域数组的一部分创建也可以基于一整个创建,甚至可以创建一个比原数组更大的切片。

package main

import "fmt"

func main() {
	// 创建一个数组
	nums := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 基于数组片段创建切片
	slice1 := nums[0:3]
	slice2 := nums[5:9]

	// 基于数组全部创建切片
	sliceAll := nums[:]

	fmt.Println(slice1)
	fmt.Println(slice2)
	fmt.Println(sliceAll)
}
切片的底层结构主要分为三个部分
  • 指针:指向底层数组起始下标
  • 长度:对应切片中元素个数,可通过len函数获取切片长度
  • 容量:切片的起始位置到底层数组的结尾位置,可通过cap函数来获取容量

基于切片

类似于基于数组创建切片,也可以基于切片来创建切片

package main

import "fmt"

func main() {
	// 创建一个数组
	nums := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 基于数组片段创建切片
	slice1 := nums[0:3]
	slice2 := nums[5:9]

	// 基于数组全部创建切片
	sliceAll := nums[:]

	// 基于切片创建切片
	slice3 := slice1[:2]

	fmt.Println(slice1)
	fmt.Println(slice2)
	fmt.Println(sliceAll)
	fmt.Println(slice3)
}
需要注意的是在切片创建时,指定的长度不可超出原底层数组的容量。如nums初始长度为10,如果基于slice1创建切片,长度就不允许超出10。

直接创建

并非一定要事先准备一个数组才能创建数组切片,Go 语言提供的内置函数 make() 可以用于灵活地创建数组切片。下面的例子示范了直接创建数组切片的各种方法:

package main

import "fmt"

func main() {
	// 创建一个数组
	nums := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 基于数组片段创建切片
	slice1 := nums[0:3]
	slice2 := nums[5:9]

	// 基于数组全部创建切片
	sliceAll := nums[:]

	// 基于切片创建切片
	slice3 := slice1[:2]

	// 直接创建,创建初始长度为10的切片。
	slice4 := make([]int, 10)

	// 直接创建,创建初始长度为10,容量为20的切片。
	slice5 := make([]int, 10, 20)

	// 还可以直接创建并初始化包含 5 个元素的数组切片
	slice6 := []int{1, 2, 3, 4,5}

	fmt.Println(slice1)
	fmt.Println(slice2)
	fmt.Println(sliceAll)
	fmt.Println(slice3)
	fmt.Println(slice4)
	fmt.Println(slice5, cap(slice5))
	fmt.Println(slice6, cap(slice6))
}

遍历数组切片

操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用 len() 函数获取元素个数,并支持使用 range 关键字来快速遍历所有元素。

package main

import "fmt"

func main() {
	// 创建一个数组
	nums := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// 基于数组片段创建切片
	slice1 := nums[0:3]
	slice2 := nums[5:9]

	// 基于数组全部创建切片
	sliceAll := nums[:]

	// 基于切片创建切片
	slice3 := slice1[:2]

	// 直接创建,创建初始长度为10的切片。
	slice4 := make([]int, 10)

	// 直接创建,创建初始长度为10,容量为20的切片。
	slice5 := make([]int, 10, 20)

	// 还可以直接创建并初始化包含 5 个元素的数组切片
	slice6 := []int{1, 2, 3, 4, 5}

	fmt.Println(slice1)
	fmt.Println(slice2)
	fmt.Println(sliceAll)
	fmt.Println(slice3)
	fmt.Println(slice4)
	fmt.Println(slice5, cap(slice5))
	fmt.Println(slice6, cap(slice6))

	for i := 0; i < len(nums); i++ {
		fmt.Println(nums[i])
	}

	for i, v := range nums {
		fmt.Println(i, v)
	}
}