Go 语言类型 数组

基本概念

数组(Array)是一组同类型元素的集合。

Go 语言中数组包含以下部分:

  • 长度:数组包含元素的数量,是数组类型的一部分。不同长度的数组是不同类型,它们之间不能互相转换。
  • 类型:数组内元素的数据类型。所有元素必须为同一类型。
  • 元素:组成数组的数据。每个数组元素都有一个编号,称为数组下标或索引。

数组属于值类型,一旦声明,类型和长度都不可修改。数组是切片和映射的基础数据结构。

声明和初始化

声明和初始化数组常用有 4 种方式,见下面示例:

package main

import "fmt"

func main() {
	// 只声明数组,元素值为数据类型的零值,之后允许赋值修改
	var a [3]int

	// 声明并部分初始化数组,用于全局定义
	var b = [3]int{1, 2}

	// 简短声明格式,同时完全初始化数组
	c := [3]int{1, 2, 3}

	// 使用 new 函数创建并初始化数组,返回指向该数组的指针
	d := new([3]int)

	// 输出:[0 0 0] [1 2 0] [1 2 3] &[0 0 0]
	fmt.Println(a, b, c, d)
}

初始化数组时,可使用 ... 替代长度值,由编译器根据元素数量自动推断长度。而在定义元素时,可用数组下标来定义值,没有定义的数组下标值为类型零值:

package main

import "fmt"

func main() {
	// 省略数组长度,由编译器推断
	a := [...]int{1, 2, 3}

	// 使用索引初始化数组元素。索引不能越界,定义顺序没要求
	b := [5]int{3: 30, 1: 10}

	// 混合模式,数组长度由元素最高索引决定
	// d 的索引跟在 2: "c" 后面所以为 3
	// e 的索引依此类推
	c := [...]string{"a", 5: "f", 2: "c", "d", "e"}

	// 输出:[1 2 3] [0 10 0 30 0] [a  c d e f]
	fmt.Println(a, b, c)
}

数组操作

由于数组长度不可变,因此很少使用,切片可以完全替代数组使用。

修改元素值

数组索引从 0 开始,可以直接通过索引修改元素值。索引必须位于边界范围之内,且只能为正整数,不支持从末尾开始索引:

package main

import "fmt"

func main() {
	// 创建包含两个整数的数组
	numbers := [2]int{1, 2}
	fmt.Println("初始第一个元素的值:", numbers[0])

	// 修改数组第一个元素值
	numbers[0] = 10
	fmt.Println("修改后第一个元素的值:", numbers[0])

	// 尝试访问或修改超出数组边界的元素将导致编译时错误
	//numbers[2] = 11 // 报错:invalid array index 2 (out of bounds for 2-element array)

	// 不支持倒序索引
	//numbers[-1] = 11 // 报错:invalid array index -1 (index must be non-negative)
}

遍历数组

使用 for 循环来遍历数组,可以配合 range 语句直接获取元素值:

package main

import (
	"fmt"
)

func main() {
	numbers := [2]int{1, 2}

	// 使用传统 for 循环通过索引遍历数组
	fmt.Println("使用传统 for 循环遍历数组:")
	for i := 0; i < len(numbers); i++ {
		fmt.Printf("索引:%d, 值:%d\n", i, numbers[i])
	}

	// 使用 range 关键字遍历数组,同时获取索引和元素值
	fmt.Println("使用 range 遍历数组:")
	for i, v := range numbers {
		fmt.Printf("索引:%d, 值:%d\n", i, v)
	}
}

传递数组

数组作为函数参数时是通过值传递:

package main

import "fmt"

func main() {
	// 调用函数,传递数组参数
	resultArray := doubleArrayValues([...]int{1, 2, 3, 4, 5})
	fmt.Println("函数返回:", resultArray)
}

// doubleArrayValues 函数接收一个整型数组,并返回一个新数组,其中每个元素值是原值两倍
func doubleArrayValues(inputArray [5]int) [5]int {
	var result [5]int
	for i, value := range inputArray {
		result[i] = value * 2
	}
	return result
}

包括将数组赋值给其他变量,也是传递数据副本:

package main

import "fmt"

func main() {
	// 初始化两个整型数组
	a := [2]int{1, 2}
	b := [2]int{3, 4}

	// 将两个数组嵌套为一个新二维数组
	nestedArray := [2][2]int{a, b}

	// 修改 b 第一个元素值
	b[0] = 100

	// 展示二维数组值,确认修改 b 不会影响 nestedArray
	fmt.Printf("a: %v, b(modified): %v, nestedArray: %v\n", a, b, nestedArray)
}

当要传递数组很大时,可以考虑传递数组指针或数组切片。

多维数组

数组本身只有一个维度,但可以组合多个数组创建多维数组。数组维度是指数组下标个数,多维数组有多个下标。多维数组中每个元素也是数组,用于表达具有依赖关系的数据(例如坐标)。下面是一个三维数组示例:

package main

import "fmt"

func main() {
	// 构造一个 2x2x2 三维数组
	threeDArray := [2][2][2]int{
		{
			{1, 2},
			{3, 4},
		},
		{
			{5, 6},
			{7, 8},
		},
	}

	// 访问和修改
	fmt.Printf("位于(1, 0, 1)的元素值为:%d\n", threeDArray[1][0][1])
	threeDArray[1][0][1] = 99
	fmt.Printf("修改后,整个三维整型数组值为:%v\n", threeDArray)
}

虽然数组 threeDArray 可以存放 2x2x2=8 个整型元素,但数组长度为 2。