Go语言切片详解

232 阅读4分钟

Go的切片类型为处理同类型数据序列提供一个方便而高效的方式。 切片有些类似于其他语言中的数组,但是有一些不同寻常的特性。 本文将深入切片的本质,并讲解它的用法。

数组

Go语言的切片是构建在数组之上的概念,我们在理解切片之前要先知道什么是数组.

与C语言基本相同,Go中的数组在定义时已经规定好了其长度,并且可以以[]这样的索引来进行访问,从0开始计数

不过不同的地方在于,Go中的数组是值语义,一个变量表示的就是整个数组而不是像C中表示数组的头一个元素的指针,当我们对数组类型进行传递的时候,传递的不是地址而是整个数组.[4]int与[5]int并不是同一个类型的数组,他们无法相互转换.

下面来看一下数组的基本用法

    //这样会创建一个数组
    //数组类型长度和容量是对等的,并且是在定义时就已经确定好了.无法变化
    //数组的访问方式跟c一样
    var a [4]int
    a[0] = 5

    b := [2]string{"Penn", "Teller"}
    b[0] = "Go"
    //b[2] = "Go" 这样会出错,因为超过了数组的容量

切片

在Go语言中,切片是我们会用的最多的类数组的数据结构,他与数组的访问方法基本相同,但是其底层的数据结构不大一样.数组是固定长度的,而切片是固定容量,长度可变的,他有两个属性值,一个叫做capacity,也就是容量,一个切片被创建时,容量也就确定了,一个叫做length,length是随着切片中元素的个数不同而动态变化的.

切片的生成

在Go语言中,主要使用内置函数make来进行创建一个切片.

//创建一个长度和容量都是5的切片,第一个参数指定类型,第二个参数指定长度
a := make([]byte,5)
len(a)//5
cap(a)//5
//创建一个长度为5,容量为10的切片,第一个参数指定类型,第二个参数指定长度,第三个参数指定容量
b := make([]byte,5,10)
len(b)//5
cap(b)//10

第一个创建的切片如下所示,第一个格子存储数据,第二个存储长度,第三个存储容量.

第二个创建的切片如下所示

切片的引用

如果学过Python的同学,应该会对这种引用方式十分熟悉.我们通过以下方式来进行切片的引用

letter := []string{"a","b","c","d","e"}
letter2 := letter[1:4]
//letter2 [b c d]
letter3 := letter[1:]
//letter3 [b c d e]
letter4 := letter[:3]
//letter4 [a b c]

如上所示,我们可以用:在[]里面进行切分,其数值遵循左闭右开原则,如果不指定值,则左值默认为0,右值默认为切片的长度(length),不过不同的是,我们无法通过指定一个负数来访问后面的元素,也不能引用超过长度的元素.

切片的增加

我们之前说到过,切片和数组的不同在于长度可变,虽然容量在创建时已经固定,但是我们可以通过内置函数append来对切片进行动态扩容以及元素的加入.我们也可以使用copy函数来进行扩容

    //增加容量的方法1,创建一个新的切片,将容量设置得大一些
    //然后复制源数组,并将新的数组的引用转到源数组
    t:= make([]string, len(letter),((cap(letter)+1)*2))
    copy(t,letter)
    letter = t;

    //增加容量的方法2,append方法
    //这是一个内置的方法,对切片进行动态扩容
    //我们只需要指定好增加的元素即可,因为其内部会动态扩容
    // num = [0 1 2 3 4 5 6]
    num := make([]int,1,1)
    num = append(num,1,2,3,4,5,6)

    // 可以这样来复制一个切片
    // num2 = [0 0 1 2 3 4 5 6]
    num2 := make([]int,0)
    num2 = append(num2,num...)
    //用这种方式来遍历切片
    for i , v := range num2 {
        num2[i] = v
    }
    fmt.Println(num2)

    // 对于数组来说,不能像切片一样被很方便地拓展
    // 所以需要通过一个显式的循环来进行复制
    // num3 = [Go Teller]
    num3 := make([]string,0)
    for _,v := range b {
        num3 = append(num3,v)
    }
    fmt.Println(num3)