Go语言中的数组

简介: 在 Go 语言中,数组是一种固定长度的、相同类型元素的序列。数组声明时长度已确定,不可改变,支持多种初始化方式,如使用 `var` 关键字、短变量声明、省略号 `...` 推断长度等。数组内存布局连续,可通过索引高效访问。遍历数组常用 `for` 循环和 `range` 关键字。

基本概念

在 Go 语言中,数组(Array)是一种固定长度的、相同类型的元素序列。数组的长度在声明时就已经确定,并且不能改变。数组的每个元素可以通过索引访问,索引从 0 开始。

数组的声明和初始化:

在 Go 语言中,数组的声明和初始化有多种方式,以下是几种常见的方式:

1. 声明并初始化数组

方式一:使用 var 关键字声明并初始化

csharp

代码解读

复制代码

var arr [5]int = [5]int{1, 2, 3, 4, 5}

方式二:使用短变量声明并初始化

go

代码解读

复制代码

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

2. 声明数组但不初始化

csharp

代码解读

复制代码

var arr [5]int

这种方式声明的数组,所有元素会被初始化为该类型的零值(例如,int 类型的零值是 0)。

3. 使用省略号 ... 自动推断数组长度

go

代码解读

复制代码

arr := [...]int{1, 2, 3, 4, 5}

这种方式会根据初始化列表中的元素个数自动推断数组的长度。

4. 部分初始化数组

go

代码解读

复制代码

arr := [5]int{1, 2}

这种方式会初始化前两个元素为 12,其余元素会被初始化为零值。

5. 指定索引初始化数组

css

代码解读

复制代码

arr := [5]int{0: 1, 4: 5}

这种方式会初始化索引为 0 的元素为 1,索引为 4 的元素为 5,其余元素会被初始化为零值。

6. 多维数组的声明和初始化

less

代码解读

复制代码

var arr [2][3]int
arr := [2][3]int{{1, 2, 3}, {4, 5, 6}}

多维数组的声明和初始化与一维数组类似,只是嵌套了更多的维度。

示例代码:

go

代码解读

复制代码

package main

import "fmt"

func main() {
    // 方式一:使用 var 关键字声明并初始化
    var arr1 [5]int = [5]int{1, 2, 3, 4, 5}
    fmt.Println(arr1)

    // 方式二:使用短变量声明并初始化
    arr2 := [5]int{1, 2, 3, 4, 5}
    fmt.Println(arr2)

    // 方式三:声明数组但不初始化
    var arr3 [5]int
    fmt.Println(arr3)

    // 方式四:使用省略号自动推断数组长度
    arr4 := [...]int{1, 2, 3, 4, 5}
    fmt.Println(arr4)

    // 方式五:部分初始化数组
    arr5 := [5]int{1, 2}
    fmt.Println(arr5)

    // 方式六:指定索引初始化数组
    arr6 := [5]int{0: 1, 4: 5}
    fmt.Println(arr6)

    // 方式七:多维数组的声明和初始化
    var arr7 [2][3]int
    arr8 := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    fmt.Println(arr7)
    fmt.Println(arr8)
}

数组的内存分析:

在 Go 语言中,数组的内存分配和布局相对简单且直观。数组是一个固定长度的、相同类型的元素序列,其内存布局是连续的。

1. 内存分配

当声明一个数组时,Go 语言会在内存中分配一块连续的内存区域,用于存储数组的元素。数组的长度在声明时就已经确定,并且不能改变。

例如,声明一个包含 5 个整数的数组:

csharp

代码解读

复制代码

var arr [5]int

在这个例子中,Go 语言会在内存中分配一块连续的内存区域,大小为 5 * sizeof(int) 字节。假设 int 类型在当前平台上占用 4 个字节,那么这块内存区域的大小就是 5 * 4 = 20 字节。

2. 内存布局

数组的内存布局是线性的,即数组的每个元素在内存中是连续存储的。数组的第一个元素存储在内存的起始位置,第二个元素紧随其后,依此类推。

例如,对于数组 arr := [5]int{1, 2, 3, 4, 5},其内存布局如下:

css

代码解读

复制代码

内存地址:  |  arr[0]  |  arr[1]  |  arr[2]  |  arr[3]  |  arr[4]  |
值:       |    1     |    2     |    3     |    4     |    5     |

每个元素的内存地址可以通过数组的基地址(即数组的第一个元素的地址)加上元素的索引和元素类型的大小来计算。

3. 访问数组元素

由于数组的内存布局是连续的,访问数组元素非常高效。通过索引访问数组元素时,Go 语言会直接计算出该元素的内存地址,并从该地址读取或写入数据。

例如,访问数组 arr 的第三个元素:

go

代码解读

复制代码

value := arr[2]

Go 语言会计算出 arr[2] 的内存地址为 arr 的基地址加上 2 * sizeof(int) 字节,然后从该地址读取数据。

4. 数组的传递

在 Go 语言中,数组是值类型,这意味着当数组作为参数传递给函数时,会进行一次完整的复制。如果数组很大,这可能会导致性能问题。

例如:

go

代码解读

复制代码

func modifyArray(arr [5]int) {
    arr[0] = 100
}

func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    modifyArray(arr)
    fmt.Println(arr)  // 输出: [1 2 3 4 5]
}

在这个例子中,modifyArray 函数接收的是 arr 的一个副本,因此修改副本不会影响原始数组。

数组的遍历:

在 Go 语言中,遍历数组有多种方式,常用的方法包括使用 for 循环和 range 关键字。以下是几种常见的遍历数组的方法:

1. 使用 for 循环和索引遍历数组

这是最基本的遍历方式,通过索引访问数组的每个元素。

go

代码解读

复制代码

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}

    for i := 0; i < len(arr); i++ {
        fmt.Println(arr[i])
    }
}

2. 使用 range 关键字遍历数组

range 关键字可以方便地遍历数组,它会返回索引和对应的元素值。

go

代码解读

复制代码

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}

    for index, value := range arr {
        fmt.Printf("Index: %d, Value: %d\n", index, value)
    }
}

3. 只使用 range 遍历数组的值

如果你只关心数组的值而不关心索引,可以使用 _ 忽略索引。

go

代码解读

复制代码

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}

    for _, value := range arr {
        fmt.Println(value)
    }
}

4. 只使用 range 遍历数组的索引

如果你只关心数组的索引而不关心值,可以只使用索引。

go

代码解读

复制代码

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}

    for index := range arr {
        fmt.Println(index)
    }
}

5. 使用 for 循环和 range 遍历多维数组

对于多维数组,可以嵌套使用 for 循环和 range 关键字。

css

代码解读

复制代码

package main

import "fmt"

func main() {
    arr := [2][3]int{{1, 2, 3}, {4, 5, 6}}

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

    // 使用 range 遍历多维数组
    for i, row := range arr {
        for j, value := range row {
            fmt.Printf("arr[%d][%d] = %d\n", i, j, value)
        }
    }
}


转载来源:https://juejin.cn/post/7428200842228547625

相关文章
|
13天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
25 7
|
12天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
13天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
88 71
|
12天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
97 67
|
15天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
86 62
|
16天前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
13天前
|
存储 Go
go语言中映射
go语言中映射
30 11
|
15天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
28 12
|
14天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
24 9
|
18天前
|
安全 Serverless Go
Go语言中的并发编程:深入理解与实践####
本文旨在为读者提供一个关于Go语言并发编程的全面指南。我们将从并发的基本概念讲起,逐步深入到Go语言特有的goroutine和channel机制,探讨它们如何简化多线程编程的复杂性。通过实例演示和代码分析,本文将揭示Go语言在处理并发任务时的优势,以及如何在实际项目中高效利用这些特性来提升性能和响应速度。无论你是Go语言的初学者还是有一定经验的开发者,本文都将为你提供有价值的见解和实用的技巧。 ####