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

1、数组(Arrays)

1.1、数组基础

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

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支持多维数组,这是一个数组的数组。一个简单的二维数组示例:

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、切片基础

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

go 复制代码
package main

import "fmt"

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

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

2.2、创建切片的几种方式

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

go 复制代码
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函数:

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

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

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

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

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

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

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

go 复制代码
slice := make([]int, 3, 5)
capacity := cap(slice) // 返回5

3.2、数组相关内置函数

  • len函数:

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

go 复制代码
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

相关推荐
zhuyasen5 小时前
当Go框架拥有“大脑”,Sponge框架集成AI开发项目,从“手写”到一键“生成”业务逻辑代码
后端·go·ai编程
写代码的比利7 小时前
Kratos 对接口进行加密转发处理的两个方法
go
chenqianghqu8 小时前
goland编译过程加载dll路径时出现失败
go
马里嗷11 小时前
Go 1.25 标准库更新
后端·go·github
郭京京12 小时前
go语言redis中使用lua脚本
redis·go·lua
心月狐的流火号16 小时前
分布式锁技术详解与Go语言实现
分布式·微服务·go
一个热爱生活的普通人18 小时前
使用 Makefile 和 Docker 简化你的 Go 服务部署流程
后端·go
HyggeBest1 天前
Golang 并发原语 Sync Pool
后端·go
来杯咖啡1 天前
使用 Go 语言别在反向优化 MD5
后端·go
郭京京2 天前
redis基本操作
redis·go