零基础 go - 44(数组)

0 阅读6分钟

go的数组是用于存放同一类型数据的集合。

数组同样是一种类型,在go中,数组是值类型,赋值和传参会进行值复制。

一、定义数组

  • var 数组名 [长度]类型
  • var 数组名: [长度]类型 = [长度]类型{元素1,元素2,...}
  • var 数组名: [长度]类型 = {元素1,元素2,...}
  • var 数组名 = [长度]类型{元素1,元素2,...}
  • var 数组名 = [长度]类型{下标: 元素, ...}
  • 数组名 := [长度]类型{元素1,元素2,下标: 元素,...}
  • var 数组名 [...]类型
  • var 数组名 [...]类型 = {元素1,元素2,...} // 让编译器根据元素个数自动推断数组长度
  • var 数组名 = [...]类型{元素1,元素2,...} // 让编译器根据元素个数自动推断数组长度
  • var 数组名 [...]类型 = [...]类型{元素1,元素2,...} // 让编译器根据元素个数自动推断数组长度
  • 数组名 := [...]类型{元素1,元素2,...} // 让编译器根据元素个数自动推断数组长度
  • 数组名 := [...]类型{下标: 元素, 下标: 元素, ...} // 让编译器根据元素个数自动推断数组长度

二、数组在内存中的存储方式

image.png

  • 数组在内存中是连续存储的,每个元素占用相同大小的内存空间。

  • 数组的第一个元素的地址和数组的地址相同,后续的元素地址=上一个元素地址 + 数组类型大小。例如,数组类型为int32,每个元素占用4字节内存空间,那么数组第一个元素地址为0x11000,第二个元素地址为0x11004,第三个元素地址为0x11008,以此类推。

  • 数组的长度是固定的,定义后不能改变。

  • 数组的地址可以通过 &数组名 获取,元素的地址可以通过 &数组名[索引] 获取。

三、数组的使用

  • 访问数组元素:数组名[索引],索引从0开始。

  • 修改数组元素:数组名[索引] = 新值。

  • 数组的长度:len(数组名)。

四、数组的遍历:

  • 普通for循环

  • for..range关键字进行遍历。

for index value := range array {
    // index是索引,value是元素值。

    // index value 都是for循环内的局部变量

    // index value 的值在每次循环时都会被重新赋值

    // index value 的地址在每次循环时不会改变,因此在循环内如果使用了index value的地址,可能会导致一些问题,例如闭包函数中使用index value的地址,可能会导致所有闭包函数都引用同一个index value变量,从而导致预期之外的结果。

    // index value 取名可以以根据实际情况进行修改,例如 for i, v := range array,i是索引,v是元素值。

    // 如果不需要使用 index 或 value,可以使用空白标识符 _ 来代替,例如 for _, v := range array,表示只使用元素值,不使用索引。
}

五、数组的注意事项

  • 数组的长度是固定的,定义后不能改变,如果需要使用可变长度的集合,可以使用切片(slice)。

  • 数组是值类型,赋值和传参会进行值复制,如果数组较大,可能会导致性能问题,可以使用指针来避免值复制,例如传递数组的指针 *[长度]类型。

image.png

  • 数组的元素类型可以是任意类型,包括基本类型、结构体、指针、接口等,但是不能混合。

  • 数组的长度必须是一个常量表达式,不能是变量或函数调用,例如 var arr [n]int 是不合法的,n必须是一个常量。

  • 数组的元素默认值为零值,例如 int类型的数组元素默认值为0,string类型的数组元素默认值为"",布尔类型的数组元素默认值为false,指针类型的数组元素默认值为nil。

  • 数组的长度可以通过内置函数 len() 获取,例如 len(arr) 返回数组 arr 的长度。

  • 数组的元素可以通过索引访问,例如 arr[0] 访问数组 arr 的第一个元素,arr[1] 访问数组 arr 的第二个元素,以此类推。如果超过了数组的长度访问元素,例如 arr[10],会导致运行时错误。

  • 数组的元素修改只能修改为同类型的值,例如 int类型的数组只能修改为 int类型的值,string类型的数组只能修改为 string类型的值,否则会导致编译错误。

  • 使用数组的步骤:

      1. 定义数组,指定数组的长度和元素类型。
      1. 初始化数组,可以在定义时直接初始化(会先赋值为零值),也可以在定义后逐个赋值。
      1. 访问和修改数组元素,可以通过索引访问和修改数组元素。
      1. 遍历数组,可以使用普通的 for循环或者 for..range循环来遍历数组元素。
  • 数组的下标从0开始,访问数组元素时需要注意索引越界的问题。

  • 如果想在函数内改变数组的内容,需要传递数组的指针,例如 func modifyArray(arr *[长度]类型)。

image.png

六、案例

package main

import "fmt"

func main() {
    // 定义一个长度为5的int类型数组,并初始化
    var arr [5]int = [5]int{1, 2, 3, 4, 5}
    // 定义一个长度为3的string类型数组,并初始化
    strArr := [3]string{"hello", "world", "golang"}
    // 定义一个长度为4的bool类型数组,并初始化
    boolArr := [...]bool{0: true, 1: false, 2: true, 3: false}
    fmt.Println("整数数组 arr =", arr)
    fmt.Println("字符串数组 strArr =", strArr)
    fmt.Println("布尔数组 boolArr =", boolArr)

    // 定义一个长度为2的结构体类型数组,并初始化
    type Person struct {
        Name string
        Age int
    }
    var personArr [2]Person = [2]Person{
        {Name: "Alice", Age: 30},
        {Name: "Bob", Age: 25},
    }
    fmt.Println("结构体数组 personArr =", personArr)




    // 访问数组元素
    fmt.Println(arr[0]) // 输出:1
    // 访问越界元素会导致运行时错误
    // fmt.Println(arr[5]) // 运行时错误:index out of range




    // 修改数组元素
    arr[0] = 10
    fmt.Println(arr[0]) // 输出:10

    //修改为不同类型的值会导致编译错误
    // arr[0] = "hello" // 编译错误:cannot use "hello" (type string) as type int in assignment





    // 遍历数组
    // 普通 for 循环
    for i := 0; i < len(arr); i++ {
        fmt.Println(arr[i])
    }

    // for..range 循环
    for index, value := range strArr {
        fmt.Printf("index: %d, value: %s\n", index, value)
    }

    // 如果不需要使用 index,可以使用空白标识符 _ 来代替
    for _, val := range strArr {
        fmt.Printf("val: %s\n", val)
    }




    // 数组作为值类型传递
    modifyArray(arr)
    fmt.Println(arr[0]) // 输出:10,数组没有被修改,因为 modifyArray 函数接收的是数组的值,而不是指针

    // 如果需要修改数组的内容,可以传递数组的指针
    modifyArray1(&arr)
    fmt.Println(arr[0]) // 输出:100,数组被修改,因为 modifyArray1 函数接收的是数组的指针
}

func modifyArray(a [5]int) {

a[0] = 100

}

func modifyArray1(a *[5]int) {

(*a)[0] = 100

}