Go语言中的复数类型:数组详解

发表时间: 2023-09-20 17:58

数组是指一系列同一类型数据的集合。 数组中包含的每个数据被称为数组元素(element), 一个数组包含的元素个数被称为数组的长度。

数组的长度必须是常量, 且是类型的组成部分。[2]int 和 [3]int 是不同类型

var n int = 10;var a [n]int //err, non-constant array bound nvar b [10]int

注意: 数组的长度不能使用变量, 但可以使用常量;

操作数组

数组的每个元素可以通过索引下标来访问, 索引下标的范围是从0开始到数组长度减1的位置。

package main //必须有个main包import (        "fmt")func main() {        var a [10]int        //数组遍历赋值        for i := 0; i < 10; i++ {            a[i] = i + 1            fmt.Printf("a[%d] = %d\n", i, a[i])        }        //数组的遍历:for        for i := 0; i < len(a); i++ {            fmt.Println("a[", i, "] = ", a[i])        }        //数组的遍历:for ... range        for i, v := range a {            fmt.Println("a[", i, "] = ", v)        }}

内置函数len(长度), cap(容量)都返回数组长度(元素数量)

package main //必须有个main包import(				"fmt")func main(){        a := [10]int{} //简短模式声明数组 {} 不能省略        fmt.Println(len(a), cap(a)) // 10 10}

初始化数组使用方法:

package main //必须有个main包import(				"fmt")func main(){        a := [3]int{1, 2} //初始化数组        b := [...]int{1, 2, 3} //通过初始化值确定数组长度        c := [5]int{2: 100, 4: 200} //通过索引号初始化元素, 未初始化元素值为0        d := [3]int{} //未初始化元素值为0, 注意: 简短声明数组 {} 括号不能省略        var f [3]int //未初始化元素值为0        fmt.Println(a, b, c, d, f) //[1 2 0] [1 2 3] [0 0 100 0 200] [0 0 0] [0 0 0]        //支持多维数组        g := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}        h := [...][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} //第二位数组不能写成"...", 只能写一个[...]        j := [4][2]int{1:{20, 21}, 3:{40, 41}}        k := [4][2]int{1:{0: 20}, 3:{1: 41}}        fmt.Println(g, h, j, k) //[[10 11] [20 21] [30 31] [40 41]] [[10 11] [20 21] [30 31] [40 41]] [[0 0] [20 21] [0 0] [40 41]] [[0 0] [20 0] [0 0] [0 41]]        var m [5]int = [5]int{1, 2, 3, 4, 5}        fmt.Println(m) //[1 2 3 4 5]        var n [5]int = [5]int{1, 2, 3, 4}        fmt.Println(n) //[1 2 3 4 0]        //var x [5]int = [5]int{1, 2, 3, 4, 5, 6}        //fmt.Println(x) //err, array index 5 out of bounds [0:5]        }

注意: 定义的数组元素的数量不能超过数组的长度

相同类型的数组之间可以使用 == 或 != 进行比较, 也可以相互赋值, 但不可以使用 < 或 >。

package main //必须有个main包import(        "fmt")func main(){        a := [3]int{1, 2, 3}        b := [3]int{1, 2, 3}        c := [3]int{1, 3}        //数组进行比较        fmt.Println(a == b, b == c) //true false        var d [3]int        //数组进行赋值操作        d = a        fmt.Println(d) //[1, 2, 3]        //不同类型(包括长度不同)的数组, 不能进行赋值        var f [4]int        //f = a //err, cannot use a (type [3]int) as type [4]int in assignment        fmt.Println(f)        //数组进行比较        fmt.Println(c == d) //err, invalid operation: c == d (mismatched types [3]int and [4]int)}

注意: 数组进行赋值或者比较时, 数组的长度和类型要相同

package main //必须有个main包import(				"fmt")func main(){        a := [5]int{1, 2, 3, 4, 5}        b := [5]int{1, 3, 2, 4, 5}        fmt.Println("a == b", a == b) //false 数组的顺序不相同返回的结果值: false}

在函数间传递数组

根据内存和性能来看, 在函数间传递数组是一个开销很大的操作。在函数之间传递变量时, 总是以值的方式传递的。

如果这个变量是一个数组, 意味着整个数组, 不管有多长, 都会完成赋值, 并传递给函数。

package main //必须有个main包import(        "fmt")func modify(array [5]int){        array[0] = 10 //试图修改数组的第一个元素        fmt.Println("In modify(), array values:", array)}func main(){        array := [5]int{1, 2, 3, 4, 5} //定义并初始化一个数组        modify(array) //In modify(), array values: [10 2 3 4 5]        fmt.Println("In modify(), array values:", array) //In modify(), array values: [1 2 3 4 5]}

数组指针作为函数的参数

package main //必须有个main包import(        "fmt")func modify(array *[5]int){        (*array)[0] = 10 //试图修改数组的第一个元素        fmt.Println("In modify(), array values:", *array)}func main(){        array := [5]int{1, 2, 3, 4, 5} //定义并初始化一个数组        modify(&array) //In modify(), array values: [10 2 3 4 5]        fmt.Println("In modify(), array values:", array) //In modify(), array values: [10 2 3 4 5]}

总结:

1. 数组:是同一种数据类型的固定长度的序列。

2. 数组定义:var a [len]int, 比如:var a [5]int, 数组长度必须是常量, 且是类型的组成部分。一旦定义, 长度不能变。

3. 长度是数组类型的一部分, 因此,var a[5] int和var a[10]int是不同的类型。

4. 数组可以通过下标进行访问, 下标是从0开始, 最后一个元素下标是:len-1

for i := 0; i < len(a); i++ {}for index, v := range a {}

5. 访问越界, 如果下标在数组合法范围之外, 则触发访问越界, 会panic

6. 数组是值类型, 赋值和传参会复制整个数组, 而不是指针。因此改变副本的值, 不会改变本身的值。

7. 支持 "=="、"!=" 操作符, 因为内存总是被初始化过的。

8. 指针数组 [n]*T, 数组指针 *[n]T。

【实例】:一维数组初始化和定义

package mainimport (				"fmt")var arr0 [5]int = [5]int{1, 2, 3}var arr1 = [5]int{1, 2, 3, 4, 5}var arr2 = [...]int{1, 2, 3, 4, 5, 6}var str = [5]string{3: "hello world", 4: "tom"}func main() {        a := [3]int{1, 2} // 未初始化元素值为 0。        b := [...]int{1, 2, 3, 4} // 通过初始化值确定数组长度。        c := [5]int{2: 100, 4: 200} // 使用引号初始化元素。        d := [...]struct {        name string        age uint8        }{        {"user1", 10}, // 可省略元素类型。        {"user2", 20}, // 别忘了最后一行的逗号。        }        fmt.Println(arr0, arr1, arr2, str)        fmt.Println(a, b, c, d)}

【实例】: 二维数组初始化和定义

package mainimport (        "fmt")var arr0 [5][3]intvar arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}func main() {        a := [2][3]int{{1, 2, 3}, {4, 5, 6}}        b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // 第 2 维度不能用 "..."。        fmt.Println(arr0, arr1)        fmt.Println(a, b)}

【实例】

[10]int 和 [20]int是不同类型([...]int 和 [5]int 是不同的数组类型)

package mainimport ("fmt")func printArray(arr *[5]int) {        arr[0] = 100        for i, v := range arr {        				fmt.Println(i, v)        }}func main() {        var arr1 [5]int        arr2 := [3]int{1, 3, 5}        arr3 := [...]int{2, 4, 6, 8, 10}        var grid [4][5]int        fmt.Println(arr1, arr2, arr3)        fmt.Println(grid)        for i := 0; i < len(arr3); i++ { //i++ 后面的要留有空                fmt.Println(arr3[i])        }        for i, v := range arr3 {                //fmt.Println(arr3[i])                fmt.Println(i, v)        }        for _, v := range arr3 {                fmt.Println(v)        }        //fmt.Printf(&arr3) //[...]int 和 [5]int 是不同的数组类型        fmt.Println(&arr1)}

解决方法: 使用切片传递变长的数据

package mainimport (        "fmt")func printArray(arr []int) {        arr[0] = 100        for i, v := range arr {        fmt.Println(i, v)        }}func main() {          var arr1 [5]int          arr2 := [3]int{1, 3, 5}          arr3 := [...]int{2, 4, 6, 8, 10}          var grid [4][5]int          fmt.Println(arr1, arr2, arr3)          fmt.Println(grid)          for i := 0; i < len(arr3); i++ { //i++ 后面的要留有空          fmt.Println(arr3[i])          }          for i, v := range arr3 {          //fmt.Println(arr3[i])          fmt.Println(i, v)          }          for _, v := range arr3 {          fmt.Println(v)          }          s := arr3[:] //使用切片的方法,解决变长的数据          printArray(s)}

【实例】

冒泡排序算法:

package main //必须有个main包import("fmt""math/rand""time")func main(){//设置种子, 只需一次//如果种子参数一样, 每次运行程序产生的随机数都一样rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数 nano: 纳米var a [10]intn := len(a)for i := 0; i < n; i++ {//产生随机数a[i] = rand.Intn(100) //100以内的随机数fmt.Printf("%d, ", a[i])}fmt.Printf("\n")//冒泡排序, 挨着的2个元素比较, 升序(大于则交换)for i := 0; i < n-1; i++ {for j := 0; j < n-1-i; j++ {if a[j] > a[j+1] {a[j], a[j+1] = a[j+1], a[j]}}}fmt.Printf("\n排序后:\n")for i := 0; i < n; i++ {fmt.Printf("%d, ", a[i])}fmt.Printf("\n")}/*6, 12, 6, 84, 32, 32, 80, 8, 38, 4,排序后:4, 6, 6, 8, 12, 32, 32, 38, 80, 84,*/


实例: 计算数组的个数

package mainimport ("fmt")func main() {        arr := []string{"apple", "orange", "apple", "banana", "orange", "banana", "apple", "apple", "orange", "apple", "banana", "orange", "banana", "apple", "apple", "orange", "apple", "banana", "orange", "banana", "apple"}        var num int = 0        for _, _ = range arr {        num++        }        fmt.Println(num) // 21, 与 cap()内建函数有着本质的区别        fmt.Println(len(arr)) // 21}

实例: 计算数组中元素的个数

package mainimport ("fmt")func main() {        arr := []string{"apple", "orange", "apple", "banana", "orange", "banana", "apple", "apple", "orange", "apple", "banana", "orange", "banana", "apple", "apple", "orange", "apple", "banana", "orange", "banana", "apple"}        m := make(map[string]int)        for _, v := range arr {        if m[v] == 0 {        m[v] = 1        } else {        m[v]++        }        }        fmt.Println(m) //map[apple:9 orange:6 banana:6]}