切片
2021/10/24 6:09:39
本文主要是介绍切片,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
十一、切片
Go 语言切片是对数组的抽象,因此切片是引用类型。但自身是结构体,值拷贝传递。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组
相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
切片本身不拥有任何数据。它们只是对现有数组的引用,但是slice 并不是数组或数组指针。它通过内部指针和相关属性引用数组片段,以实现变长方案。
切片遍历方式和数组一样,可以用len()求长度。表示可用元素数量,读写操作不能超过该限制。
1 切片的定义
你可以声明一个未指定大小的数组来定义切片,切片不需要说明长度。
var 变量名 []类型 // 比如 var str []string // var arr []int。 // []括号内什么都不写 就是切片类型
或使用 make() 函数来创建切片:
var slice []type = make([]type, len) // 也可以简写为,其中 capacity 为可选参数。这里 len 是数组的长度并且也是切片的初始长度 slice := make([]type, len) slice := make([]type, length, capacity)
2 创建切片的各种方式
func main() { //1.声明切片 var s1 []int if s1 == nil { fmt.Println("是空") } else { fmt.Println("不是空") } // 2.:= s2 := []int{} // 3.make() var s3 []int = make([]int, 0) fmt.Println(s1, s2, s3) // 4.初始化赋值 var s4 []int = make([]int, 0, 0) fmt.Println(s4) s5 := []int{1, 2, 3} fmt.Println(s5) // 5.从数组切片 arr := [5]int{1, 2, 3, 4, 5} // 定义数组 var s6 []int // 定义切片 // 索引区间前闭后开 s6 = arr[1:4] fmt.Println(s6) }
一个切片在未初始化之前默认为 nil,长度为 0。
3 切片初始化
s :=[] int {1,2,3 }
直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。
var arr = [...]int{0,1,2,3,4,5,6,7,8,9,} var slice0 []int = arr[start:end] var slice1 []int = arr[:end] var slice2 []int = arr[start:] var slice3 []int = arr[:] var slice4 = arr[:len(arr)-1]
举例:
var arr = [...]int{0,1,2,3,4,5,6,7,8,9,} var slice0 []int = arr[2:8] // 左闭右开,len=high-low var slice1 []int = arr[0:6] //0可以省略: var slice []int = arr[:end] var slice2 []int = arr[5:10] //如果切片到结尾,可以省略: var slice[]int = arr[start:] var slice3 []int = arr[0:len(arr)] //var slice []int = arr[:] var slice4 = arr[:len(arr)-1] //去掉切片的最后一个元素 fmt.Printf("arr %v\n", arr) fmt.Printf("slice0 %v\n", slice0) fmt.Printf("slice1 %v\n", slice1) fmt.Printf("slice2 %v\n", slice2) fmt.Printf("slice3 %v\n", slice3) fmt.Printf("slice4 %v\n", slice4) // 输出: arr [0 1 2 3 4 5 6 7 8 9] slice0 [2 3 4 5 6 7] slice1 [0 1 2 3 4 5] slice2 [5 6 7 8 9] slice3 [0 1 2 3 4 5 6 7 8 9] slice4 [0 1 2 3 4 5 6 7 8]
4 len() 和 cap() 函数
切片是可索引的,并且可以由 len() 方法获取长度。
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
以下为具体实例:
package main import "fmt" func main() { var numbers = make([]int,3,5) printSlice(numbers) } func printSlice(x []int){ fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) } // 输出 len=3 cap=5 slice=[0 0 0]
5 追加切片元素
正如我们已经知道数组的长度是固定的,它的长度不能增加。 切片是动态的,使用 append
可以将新元素追加到切片上。append 函数的定义是
func append(s[]T,x ... T)[]T // x … T 在函数定义中表示该函数接受参数 x 的个数是可变的。这些类型的函数被称为[可变函数]。 // append :向 slice 尾部添加数据,返回新的 slice 对象。
如果切片由数组支持,并且数组本身的长度是固定的,那么切片如何具有动态长度。以及内部发生了什么?
当新的元素被添加到切片时,会创建一个新的数组。现有数组的元素被复制到这个新数组中,并返回这个新数组的新切片引用。
新切片的容量是旧切片的两倍。
举例:
cars := []string{"Ferrari", "Honda", "Ford"} fmt.Println("cars:", cars, "has old length", len(cars), "and capacity", cap(cars)) // capacity of cars is 3 cars = append(cars, "Toyota") fmt.Println("cars:", cars, "has new length", len(cars), "and capacity", cap(cars)) // capacity of cars is doubled to 6 // 输出 cars: [Ferrari Honda Ford] has old length 3 and capacity 3 cars: [Ferrari Honda Ford Toyota] has new length 4 and capacity 6
6 切片的长度和容量
切片的长度是切片中的元素数。
切片的容量是从创建切片索引位置开始的底层数组中元素数。
7 copy() 函数和内存优化
切片持有对底层数组的引用。只要切片在内存中,数组就不能被垃圾回收。在内存管理方面,这是需要注意的。让我们假设我们有一个非
常大的数组,我们只想处理它的一小部分。然后,我们由这个数组创建一个切片,并开始处理切片。这里需要重点注意的是,在切片引用
时数组仍然存在内存中。
一种解决方法是使用 [copy] 函数 func copy(dst,src[]T)int
来生成一个切片的副本。这样我们可以使用新的切片,原始数组可以被
垃圾回收。
func countries() []string { countries := []string{"USA", "Singapore", "Germany", "India", "Australia"} neededCountries := countries[:len(countries)-2] // 创建一个去掉尾部 2 个元素的切片 countriesCpy := make([]string, len(neededCountries)) copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy return countriesCpy } func main() { countriesNeeded := countries() fmt.Println(countriesNeeded) } //现在 countries 数组可以被垃圾回收, 因为 neededCountries 不再被引用。
8 切片的函数传递
切片在内部可由一个结构体类型表示。这是它的表现形式,
type slice struct { Length int Capacity int ZerothElement *byte }
切片包含长度、容量和指向数组第零个元素的指针。当切片传递给函数时,即使它通过值传递,指针变量也将引用相同的底层数组。因
此,当切片作为参数传递给函数时,函数内所做的更改也会在函数外可见。
这篇关于切片的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)
- 2024-05-31全网首发!软考2024年5月《软件设计师》真题+解析+答案!(21-30题)