身为复合值的数组


在 Go 中,数组的长度固定,是个复合值,元素的类型及个数决定了数组的类型,在内存中使用连续空间配置。

创建与访问数组

创建数组的方式是[n]type,其中n为数组的元素数量,type是元素的类型。例如:

package main

import "fmt"

func main() {
    var scores [10]int
    scores[0] = 90
    scores[1] = 89
    fmt.Println(scores)      // [90 89 0 0 0 0 0 0 0 0]
    fmt.Println(len(scores)) // 10
}

在上面的程序中,创建了具有 10 个元素的数组,可以用来存储int类型的值,可透过scores变量指定索引来访问元素,scores变量的类型为[10]int,记得,长度也是数组的类型的一部份,若一个数组为[10]int,而另一个数组为[5]int,这两个数组会是不同的类型,像上头这样定义数组,默认每个元素都会初始化为 0。

数组使用索引访问,如同其他语言的惯例,索引从 0 开始,len函数可以获取数组的长度,如果想在创建数组时指定初始化,可以如下:

package main

import "fmt"

func main() {
    arr1 := [3]int{1, 2, 3}
    arr2 := [5]int{1, 2, 3}
    arr3 := [...]int{1, 2, 3, 4, 5}
    fmt.Println(arr1) // [1 2 3]
    fmt.Println(arr2) // [1 2 3 0 0]
    fmt.Println(arr3) // [1 2 3 4 5]
}

在上头可以看到,如果定义的元素数量不足[]中指定的数量,那么会自动给予初值,也可以使用...,或者只写[],让编译器自动判断数量,如果定义的元素数量超过[]中指定的数量,那么会有 out of bounds 的编译错误。

数组指定与比较

在 Go 中,数组指定会逐一复制值,例如:

package main

import "fmt"

func main() {
    arr1 := [...]int{1, 2, 3}
    arr2 := arr1
    fmt.Println(arr1) // [1 2 3]
    fmt.Println(arr2) // [1 2 3]
    arr1[0] = 10
    fmt.Println(arr1) // [10 2 3]
    fmt.Println(arr2) // [1 2 3]
}

在调用函数时若传递数组给参数,或者是返回数组,也是做复制的动作。数组可以使用==!=进行比较,由于长度也是数组类型的一部份,因此,只要长度与元素类型相同的数组才可以做比较,如果将[3]int[5]int做比较,会发生 mismatched types 编译错误,同样的,指定数组给另一数组时,也必须是相同类型的数组。

嵌套数组

Go 的数组是线性的,如果想模拟多维,可以使用嵌套数组。例如,创建一个二维数组:

package main

import "fmt"

func main() {
    var arr [2][3]int
    fmt.Println(arr)   // [[0 0 0] [0 0 0]]
}

显然地,第一个[]中数字指定了数组中会有两个[3]int数组,因此,若要同时定义数组中的元素,可以如下:

package main

import "fmt"

func change(arr [3]int) [3]int {
    arr[0] = 10
    return arr
}

func main() {
    arr1 := [2][3]int{[3]int{1, 2, 3}, [3]int{4, 5, 6}}
    fmt.Println(arr1) // [[1 2 3] [4 5 6]]

    arr2 := [...][3]int{[...]int{1, 2, 3}, [...]int{4, 5, 6}}
    fmt.Println(arr2) // [[1 2 3] [4 5 6]]

    arr3 := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    fmt.Println(arr3) // [[1 2 3] [4 5 6]]

    arr4 := [...][3]int{{1, 2, 3}, {4, 5, 6}}
    fmt.Println(arr4) // [[1 2 3] [4 5 6]]
}

上头一口气示范了几种嵌套数组的定义方式,基本上后两种应该是比较容易编写的,由于数组的长度是类型的一部份,必须在定义时指定,因此,就二维数组来说,一定都是方阵。

遍历数组

想要逐一遍历数组的话,基本上可以使用for循环,例如:

package main

import "fmt"

func main() {
    arr := [...]int{1, 2, 3}
    for i := 0; i < len(arr); i++ {
        fmt.Printf("%d\n", arr[i])
    }
}

另一个方式是使用for range

package main

import "fmt"

func main() {
    arr := [...]int{1, 2, 3}
    for index, element := range arr {
        fmt.Printf("%d: %d\n", index, element)
    }
}

在不需要索引的情况下,可以使用_忽略返回的索引值,例如:

package main

import "fmt"

func main() {
    arr := [...]int{1, 2, 3}
    for _, element := range arr {
        fmt.Printf("%d\n", element)
    }
}




展开阅读全文