likes
comments
collection
share

Go基础:我对数组和切片的理解

作者站长头像
站长
· 阅读数 18

1、数组(Arrays)

1.1、数组基础

在Go中,数组是一组相同类型元素的集合。让我们看一个简单的例子:

package main

import "fmt"

func main() {
    // 定义一个包含5个整数的数组
    var numbers [5]int

    // 初始化数组元素
    for i := 0; i < 5; i++ {
        numbers[i] = i * 2
    }

    // 打印数组元素
    fmt.Println(numbers)
}

1.2、多维数组

Go支持多维数组,这是一个数组的数组。一个简单的二维数组示例:

package main

import "fmt"

func main() {
    // 定义一个2x3的二维数组
    var matrix [2][3]int

    // 初始化二维数组元素
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            matrix[i][j] = i + j
        }
    }

    // 打印二维数组
    fmt.Println(matrix)
}

2、切片(Slices)

2.1、切片基础

切片是对数组的抽象,是一种更灵活的数据结构。让我们看一个简单的切片示例:

package main

import "fmt"

func main() {
    // 创建一个切片
    numbers := []int{1, 2, 3, 4, 5}

    // 打印切片元素
    fmt.Println(numbers)
}

2.2、创建切片的几种方式

下面的示例是创建切片的一些常见方式。根据不同的场景和需求,选择适合你情况的方式。

package main

import "testing"

// 直接初始化切片
func TestSliceCreate1(t *testing.T) {
   slice := []int{1, 2, 3, 4}
   t.Log(slice)
}

// 使用 make 函数创建切片,指定长度和容量
func TestSliceCreate2(t *testing.T) {
   slice1 := make([]int, 3, 5) // 长度为3,容量为5
   t.Log(slice1)

   slice2 := make([]int, 5) // 长度和容量都是5
   t.Log(slice2)
}

// 通过切片表达式,可以从数组或切片中创建一个新的切片
func TestSliceCreate3(t *testing.T) {
   arr := [4]int{1, 2, 3, 4}
   slice := arr[1:4]

   t.Log(arr)
   t.Log(slice)
}

// 使用`append`函数可以向切片动态添加元素
func TestSliceCreate4(t *testing.T) {
   slice1 := []int{1, 2, 3, 4}
   slice2 := append(slice1, 5, 6, 7)
   t.Log(slice1)
   t.Log(slice2)
}

// 通过使用`copy`函数,你可以从一个切片中复制元素到另一个切片,从而创建一个新的切片
func TestSliceCreate5(t *testing.T) {
   slice1 := []int{1, 2, 3, 4}
   slice2 := make([]int, len(slice1))
   copy(slice2, slice1)
   t.Log(slice2)
}

// 可以使用`[:]`操作符从数组或切片中创建一个新的切片
func TestSliceCreate6(t *testing.T) {
   arr := [4]int{1, 2, 3, 4}
   slice := arr[:]
   t.Log(slice)
}

3、操作数组和切片的内置函数有哪些

3.1、切片相关内置函数

  • make函数:

用于创建切片,可以指定切片的长度和容量。

slice := make([]int, 3, 5) // 创建长度为3,容量为5的切片
  • append函数: 用于在切片末尾追加元素,可以同时追加多个元素。
slice := []int{1, 2, 3}
slice = append(slice, 4, 5, 6)
  • copy函数:

用于将源切片的元素复制到目标切片,返回复制的元素个数。

slice1 := []int{1, 2, 3}
slice2 := make([]int, len(slice1))
copy(slice2, slice1)
  • len函数:

返回切片的长度,表示切片中元素的个数。

slice := []int{1, 2, 3, 4, 5}
length := len(slice) // 返回5
  • cap函数:

返回切片的容量,表示切片中可以存储的最大元素个数。

slice := make([]int, 3, 5)
capacity := cap(slice) // 返回5

3.2、数组相关内置函数

  • len函数:

返回数组的长度,表示数组中元素的个数。

go
arr := [5]int{1, 2, 3, 4, 5}
length := len(arr) // 返回5

注意: 由于数组是固定长度的,没有动态增长的能力,因此没有像切片那样的append函数。

4、切片的动态调整和底层数组的关系是什么

切片是基于数组的一种抽象。切片包含三个关键属性:指向底层数组的指针、切片的长度和切片的容量。

  1. 指向底层数组的指针: 切片本身并不存储数据,而是通过指针引用底层数组的一部分。这意味着对切片的操作实际上是对底层数组的操作。
  2. 切片的长度: 表示切片中的元素数量。它可以动态增长,但不能超过底层数组的容量。
  3. 切片的容量: 表示切片最多可以容纳的元素数量,包括从切片的开始位置到底层数组的末尾的元素。容量的增长也受到底层数组容量的限制。

动态调整的过程:

  1. 初始创建: 当使用切片表达式或make函数创建一个切片时,它会指向底层数组的全部元素。
  2. 追加元素: 当使用append函数向切片追加元素时,如果切片的长度小于底层数组的容量,直接在底层数组上添加元素。如果长度超过了容量,Go会创建一个新的底层数组,并将原有的元素复制到新数组中,然后在新数组上添加元素。
  3. 切片的长度和容量: 切片的长度会根据追加的元素动态增长,而容量取决于底层数组的容量。容量的增长也是动态的,但不能超过底层数组的容量。

这种机制使得切片能够在不需要手动管理内存的情况下动态增长,同时避免了过多的数组复制。由于切片是对底层数组的引用,任何对切片的修改都会影响到底层数组,反之,也是这样。

需要注意的是,当多个切片共享同一个底层数组时,对其中一个切片的修改会影响到其他切片,因为它们共享相同的内存空间。这是在使用切片时需要注意的一点。

参考资料

Go语言官方文档:ArraysSlices

A Tour of Go:ArraysSlices

Go by Example: ArraysSlices

The Go Programming Language Specification: ArraysSlices