切片

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
}

切片包含长度、容量和指向数组第零个元素的指针。当切片传递给函数时,即使它通过值传递,指针变量也将引用相同的底层数组。因

此,当切片作为参数传递给函数时,函数内所做的更改也会在函数外可见。



这篇关于切片的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程