数组是 Go 语言中最基本的数据结构之一。本章将详细介绍数组的声明、初始化、遍历和使用方法。

什么是数组?

数组是固定长度的、存储相同类型元素的序列。

可以把数组想象成一排连续的储物柜:

索引:    0      1      2      3      4
       ┌──────┬──────┬──────┬──────┬──────┐
数组:  │  10  │  20  │  30  │  40  │  50  │
       └──────┴──────┴──────┴──────┴──────┘

数组的特点

特点说明
固定长度声明后长度不可改变
相同类型所有元素必须是同一类型
值类型赋值和传参会复制整个数组
连续内存元素在内存中连续存储

数组声明

方式一:声明但不初始化

var 数组名 [长度]类型

示例:

package main

import "fmt"

func main() {
    var nums [5]int
    var names [3]string
    var flags [4]bool

    fmt.Printf("nums: %v\n", nums)
    fmt.Printf("names: %v\n", names)
    fmt.Printf("flags: %v\n", flags)
}

输出:

nums: [0 0 0 0 0]
names: [  ]
flags: [false false false false]

注意:数组声明后,元素会自动初始化为零值。

方式二:声明并初始化

var 数组名 = [长度]类型{元素1, 元素2, ...}

示例:

package main

import "fmt"

func main() {
    var nums = [5]int{10, 20, 30, 40, 50}
    var names = [3]string{"张三", "李四", "王五"}

    fmt.Printf("nums: %v\n", nums)
    fmt.Printf("names: %v\n", names)
}

输出:

nums: [10 20 30 40 50]
names: [张三 李四 王五]

方式三:短变量声明

数组名 := [长度]类型{元素1, 元素2, ...}

示例:

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}
    names := [3]string{"张三", "李四", "王五"}

    fmt.Printf("nums: %v\n", nums)
    fmt.Printf("names: %v\n", names)
}

方式四:自动推断长度

使用 ... 让编译器自动计算长度:

package main

import "fmt"

func main() {
    nums := [...]int{10, 20, 30, 40, 50}
    names := [...]string{"张三", "李四", "王五"}

    fmt.Printf("nums 长度: %d, 值: %v\n", len(nums), nums)
    fmt.Printf("names 长度: %d, 值: %v\n", len(names), names)
}

输出:

nums 长度: 5, 值: [10 20 30 40 50]
names 长度: 3, 值: [张三 李四 王五]

方式五:指定索引初始化

可以指定索引位置初始化:

package main

import "fmt"

func main() {
    nums := [5]int{0: 10, 2: 30, 4: 50}

    fmt.Printf("nums: %v\n", nums)
}

输出:

nums: [10 0 30 0 50]

访问数组元素

使用索引访问数组元素,索引从 0 开始:

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}

    fmt.Printf("第一个元素: %d\n", nums[0])
    fmt.Printf("第三个元素: %d\n", nums[2])
    fmt.Printf("最后一个元素: %d\n", nums[4])

    nums[0] = 100
    fmt.Printf("修改后的第一个元素: %d\n", nums[0])
}

输出:

第一个元素: 10
第三个元素: 30
最后一个元素: 50
修改后的第一个元素: 100

索引越界

访问超出范围的索引会报错:

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}
    fmt.Println(nums[5])
}

错误信息:

invalid array index 5 (out of bounds for 5-element array)

遍历数组

方式一:for 循环

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}

    for i := 0; i < len(nums); i++ {
        fmt.Printf("索引: %d, 值: %d\n", i, nums[i])
    }
}

方式二:for-range(推荐)

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}

    for index, value := range nums {
        fmt.Printf("索引: %d, 值: %d\n", index, value)
    }
}

只要索引或值

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}

    fmt.Println("只要值:")
    for _, value := range nums {
        fmt.Printf("值: %d\n", value)
    }

    fmt.Println("\n只要索引:")
    for index := range nums {
        fmt.Printf("索引: %d\n", index)
    }
}

多维数组

Go 支持多维数组,最常见的是二维数组。

声明二维数组

package main

import "fmt"

func main() {
    var matrix [3][4]int

    for i := 0; i < 3; i++ {
        for j := 0; j < 4; j++ {
            matrix[i][j] = i*4 + j + 1
        }
    }

    fmt.Println("二维数组:")
    for _, row := range matrix {
        fmt.Println(row)
    }
}

输出:

二维数组:
[1 2 3 4]
[5 6 7 8]
[9 10 11 12]

初始化二维数组

package main

import "fmt"

func main() {
    matrix := [3][3]int{
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9},
    }

    fmt.Println("矩阵:")
    for _, row := range matrix {
        fmt.Println(row)
    }
}

输出:

矩阵:
[1 2 3]
[4 5 6]
[7 8 9]

数组是值类型

数组是值类型,赋值和传参会复制整个数组:

package main

import "fmt"

func modifyArray(arr [3]int) {
    arr[0] = 100
    fmt.Printf("函数内: %v\n", arr)
}

func main() {
    nums := [3]int{1, 2, 3}
    fmt.Printf("原始数组: %v\n", nums)

    modifyArray(nums)
    fmt.Printf("调用后: %v\n", nums)
}

输出:

原始数组: [1 2 3]
函数内: [100 2 3]
调用后: [1 2 3]

注意:函数内修改的是副本,不影响原数组。

传递数组指针

如果需要修改原数组,传递指针:

package main

import "fmt"

func modifyArray(arr *[3]int) {
    arr[0] = 100
    fmt.Printf("函数内: %v\n", *arr)
}

func main() {
    nums := [3]int{1, 2, 3}
    fmt.Printf("原始数组: %v\n", nums)

    modifyArray(&nums)
    fmt.Printf("调用后: %v\n", nums)
}

输出:

原始数组: [1 2 3]
函数内: [100 2 3]
调用后: [100 2 3]

数组比较

相同类型的数组可以使用 ==!= 比较:

package main

import "fmt"

func main() {
    a := [3]int{1, 2, 3}
    b := [3]int{1, 2, 3}
    c := [3]int{1, 2, 4}

    fmt.Printf("a == b: %v\n", a == b)
    fmt.Printf("a == c: %v\n", a == c)
}

输出:

a == b: true
a == c: false

注意:长度不同的数组是不同类型,无法比较。

数组长度

使用 len() 获取数组长度:

package main

import "fmt"

func main() {
    nums := [5]int{10, 20, 30, 40, 50}
    fmt.Printf("数组长度: %d\n", len(nums))
}

实际案例

案例 1:找出最大值和最小值

package main

import "fmt"

func main() {
    nums := [...]int{64, 34, 25, 12, 22, 11, 90}

    max, min := nums[0], nums[0]

    for _, num := range nums {
        if num > max {
            max = num
        }
        if num < min {
            min = num
        }
    }

    fmt.Printf("数组: %v\n", nums)
    fmt.Printf("最大值: %d\n", max)
    fmt.Printf("最小值: %d\n", min)
}

输出:

数组: [64 34 25 12 22 11 90]
最大值: 90
最小值: 11

案例 2:冒泡排序

package main

import "fmt"

func main() {
    nums := [...]int{64, 34, 25, 12, 22, 11, 90}

    fmt.Printf("排序前: %v\n", nums)

    n := len(nums)
    for i := 0; i < n-1; i++ {
        for j := 0; j < n-i-1; j++ {
            if nums[j] > nums[j+1] {
                nums[j], nums[j+1] = nums[j+1], nums[j]
            }
        }
    }

    fmt.Printf("排序后: %v\n", nums)
}

输出:

排序前: [64 34 25 12 22 11 90]
排序后: [11 12 22 25 34 64 90]

案例 3:数组求和和平均值

package main

import "fmt"

func main() {
    nums := [...]int{10, 20, 30, 40, 50}

    sum := 0
    for _, num := range nums {
        sum += num
    }

    avg := float64(sum) / float64(len(nums))

    fmt.Printf("数组: %v\n", nums)
    fmt.Printf("总和: %d\n", sum)
    fmt.Printf("平均值: %.2f\n", avg)
}

输出:

数组: [10 20 30 40 50]
总和: 150
平均值: 30.00

数组的局限性

局限说明
固定长度无法动态添加或删除元素
值类型传参会复制整个数组,效率低
类型固定只能存储一种类型

解决方案:使用切片(Slice),它更灵活,是 Go 中更常用的数据结构。

总结

本章学习了 Go 语言的数组:

知识点说明
声明var arr [n]Tarr := [...]T{...}
访问arr[index],索引从 0 开始
遍历for-range 循环
长度len(arr)
类型值类型,赋值和传参会复制
比较相同类型可以用 == 比较