Go 语言的切片使用
Posted 小伍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go 语言的切片使用相关的知识,希望对你有一定的参考价值。
切片(slice)是建立在数组之上的更方便,更灵活,更强大的数据结构。切片并不存储任何元素而只是对现有数组的引用。
切片的三要素
- 指向数组中的开始位置
- 切片的长度,通过内置函数len获得
- 切片的最大容量,通过内置函数cap获得
可以认为切片在内部表示为如下的结构体:
type slice struct {
// 长度
Length int
// 容量
Capacity int
// 指向首元素的指针
ZerothElement *byte
}
切片声明
// 基于数组创建一个从 a[start] 到 a[end -1] 的切片
a := [5]int{76, 77, 78, 79, 80}
var b []int = a[1:4]
// 创建了一个长度为4的string数组,并返回一个切片给names
names := []string{"beijing", "shanghai", "guangzhou", "shenzhen"}
// 创建长度为10的字符串切片
str := make([]string, 10)
// 创建长度为10,容量为20的字符串切片
str := make([]string, 10, 20)
arr[start:end] 的使用
// 基于数组产生新的切片,a[start:end]为左闭右开
name1 := names[0:3]
name2 := names[:3]
name3 := names[2:]
name4 := names[:]
引用传递
切片本身不包含任何数据。它仅仅是底层数组的一个上层表示。对切片进行的任何修改都将反映在底层数组中。
names := []string{"beijing", "shanghai", "guangzhou", "shenzhen"}
name1 := names[0:3]
// 引用传递,会同时改变原数组
name1[2] = "luoyang"
fmt.Println(names)
fmt.Println(name1)
获取切片长度与容量
str := "helloworld"[5:7]
fmt.Println("len:", len(str), ", cap:", cap(str))
切片追加元素
// append会判断切片是否有剩余空间,如果没有剩余空间,则会自动扩充两倍空间
names = append(names, "chongqing")
如果切片是建立在数组之上的,而数组本身不能改变长度,那么切片是如何动态改变长度的呢?实际发生的情况是,当新元素通过调用append
函数追加到切片末尾时,如果超出了容量,append
内部会创建一个新的数组。并将原有数组的元素被拷贝给这个新的数组,最后返回建立在这个新数组上的切片。这个新切片的容量是旧切片的二倍。
切片追加切片
可以使用 ...
操作符将一个切片追加到另一个切片末尾
veggies := []string{"potatoes","tomatoes","brinjal"}
fruits := []string{"oranges","apples"}
food := append(veggies, fruits...)
fmt.Println("food:", food)
遍历切片
for key, value := range names {
fmt.Println("key:", key, ", value:", value)
}
复制切片
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个位置
切片作为函数参数
func subtactOne(numbers []int) {
for i := range numbers {
numbers[i] -= 2
}
}
func main() {
nos := []int{8, 7, 6}
fmt.Println("slice before function call", nos)
subtactOne(nos) //function modifies the slice
fmt.Println("slice after function call", nos) //modifications are visible outside
}
// array before function call [8 7 6]
// array after function call [6 5 4]
切片内存优化
切片保留对底层数组的引用。只要切片存在于内存中,数组就不能被垃圾回收。假设我们有一个非常大的数组,而我们只需要处理它的一小部分,为此我们创建这个数组的一个切片,并处理这个切片。这时候数组仍然存在于内存中,因为切片正在引用它。
解决该问题的一个方法是使用 copy 函数来创建该切片的一个拷贝。这样我们就可以使用这个新的切片,原来的数组可以被垃圾回收。
func countries() []string {
countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
// 数组被切片引用,不能回收
neededCountries := countries[:len(countries)-2]
// 创建新的切片
countriesCpy := make([]string, len(neededCountries))
// 使用 copy 函数创建切片的拷贝
copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy
// 返回后数组不再被引用,自动回收
return countriesCpy
}
func main() {
countriesNeeded := countries()
fmt.Println(countriesNeeded)
}
以上是关于Go 语言的切片使用的主要内容,如果未能解决你的问题,请参考以下文章