Go语言基础之数组切片

目录:

概述

基于数组,数组切片天界了一系列管理功能,可以随时动态扩充存放空间,并且可以随意传递而不会导致所管理的元素被重复复制。

数组切片的数据结构可以抽象为以下3个变量:

  • 一个指向原生数组的指针
  • 数组切片中的元素个数
  • 数组切片已分配的存储空间

创建数组切片

创建数组切片的方法主要有两种:

基于数组

数组切片可以基于一个已存在的数组创建,数组切片可以只使用数组的一部分元素或者整个数组来创建。

package main

import (
    "fmt"
)

func main() {
    var array1 = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    var arraySlice = array1[:5]
    fmt.Println("elements of array1:")
    for _, v := range array1 {
        fmt.Print(v, " ")
    }
    fmt.Println("\nelements of arraySlice:")
    for _, v := range arraySlice {
        fmt.Print(v, " ")
    }
}

通过数组的下标范围,创建切片

直接创建

通过内置函数make()可以灵活的创建数组切片。

mySlice := make([]int, 5)           //创建一个初始元素为5的数组切片,元素的初始值为0,
mySlice1 := make([]int, 5, 10)      //创建一个初始元素为5的数组切片,元素的初始值为0,并预留10个元素的存储空间
mySlice2 := []int{1, 2, 3, 4, 5}     //直接创建并初始化包含5个元素的数组切片。

元素遍历

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

动态增减元素

可动态增减元素个数是数组切片比数组更为强大的功能。与数组相比,数组切片多了一个存储能力(capacity)的概念,即元素个数和分配空间可以是两个不同的值。合理的设置存储能力的值,可以大幅降低数组切片内部重新分配内存块的频率,从而大大提高程序的性能。

数组切片支持GO语言内置的cap()len()函数,cap()函数返回的是数组切片分配的空间大小,len()函数返回的是数组切片中当前所存储的元素个数。

package main

import "fmt"

func main() {
    slice1 := make([]int, 5, 10)

    fmt.Println("len(slice1):", len(slice1))
    fmt.Println("cap(slice1):", cap(slice1))
}
// len(slice1): 5
// cap(slice1): 10

数组切片通过append()函数添加元素,其中,第二个参数是一个不定参数,可根据需求添加如干个元素。甚至可以直接将一个数组切片追加到一个数组切片的末尾

slice1 = append(slice1, 1, 2, 3, 4)
slice2 := []int{8, 9}
slice1 = append(slice1, slice2...)

需要注意的是slice2...中的...,如果没有这个省略号,则会编译报错,这里的左右就是将slice2包含的所有元素打散后传入slice1

数组切片会自动处理存储空间不足的问题。可以通过查看$GOROOT/src/runtime/slice.go源码,其中扩容相关代码如下:

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
    newcap = cap
} else {
    if old.len < 1024 {
        newcap = doublecap
    } else {
        // Check 0 < newcap to detect overflow
        // and prevent an infinite loop.
        for 0 < newcap && newcap < cap {
            newcap += newcap / 4
        }
        // Set newcap to the requested cap when
        // the newcap calculation overflowed.
        if newcap <= 0 {
            newcap = cap
        }
    }
}

基于数组切片创建数组切片

类似于数组切片可以基于一个数组创建,数组切片也可以基于另一个数组切片创建。

oldSlice := []int{1, 2, 3, 4, 5}
newSlice := oldSlice[:3]

其中,选择oldSlice的元素范围可以超过所以包含的元素个数,但是不能超过oldSlice的存储能力(cap()返回的值),超出oldSlice元素的个数部分会使用0补充。

内容复制

通过内置函数copy(),将内容从一个数组切片复制到另一个数组切片。如果两个数组切片不一样大,则会按照较小的数组切片的元素个数进行复制。

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
cpoy(slice2, slice1)     //只会将slice1的前三个元素复制到slice2中
cpoy(slice1, slice2)     //只会将slice2的三个元素复制到slice1的前三个位置