《Go程序设计语言》学习笔记之数组

《Go程序设计语言》学习笔记之数组

 一. 环境

  Centos8.5, go1.17.5 linux/amd64

 

二. 概念

  数组是具有固定长度且拥有零个或多个相同数据类型元素的序列。

 

三. 声明

声明一个数组a,然后打印数组、数组a的长度、数组a的类型。从打印的a的类型中可以看出数组的长度是类型的一部分

// test sample
package main

import (
    "fmt"
)

func main() {
    var a [3]int
    fmt.Printf("a: %d\n", a)
    fmt.Printf("len: %d\n", len(a))
    fmt.Printf("type: %T\n", a)
}

运行结果如下

 

 

 四. 初始化

声明与初始化个人感觉是C/C++中的说法,严格来说在Go中不太严谨。在Go中,定义的变量,如果没有显式初始化的话,变量会默认初始化。也就是说,声明即是初始化。Go中有个零值机制。零值机制保障所有的变量是良好定义的,Go里面不存在未初始化变量。

下面示例了4种初始化的方式

第一种,声明了一个长度为3的整型数组a,从打印结果来看, 每个元素初始值为零值。

第二种,声明了一个长度为3的整型数组b,使用数组字面量初始化一个数组。字面量数组中只有两个元素,但是数组b的长度为3,最后一个元素的初始值为零值。

第三种,使用短变量声明的形式,使用数组字面量来初始化整型数组c,数组字面量中的长度是”...“,则数组的长度由初始化数组的元素个数决定。

第四种,先使用常量计数器iota声明一组常量值作为下标,然后将下标与对应位置上的元素的值对应起来。这种的方式好处就是索引可以按照任意顺序出现。

 8 func main() {
  9     // init way1, zero value
 10     var a [3]int
 11     for _, v := range a {
 12         fmt.Printf("%d\t", v)
 13     }
 14     fmt.Printf("\n")
 15
 16     // init way2
 17     fmt.Println("----------")
 18     var b [3]int = [3]int{1, 2}
 19     for _, v := range b {
 20         fmt.Printf("%d\t", v)
 21     }
 22     fmt.Printf("\n")
 23
 24     // init way3
 25     fmt.Println("----------")
 26     c := [...]int{4, 5, 6}
 27     for _, v := range c {
 28         fmt.Printf("%d\t", v)
 29     }
 30     fmt.Printf("\n")
 31
 32     // init way4
 33     fmt.Println("----------")
 34     type Currency int
 35
 36     const (
 37         USD Currency = iota
 38         EUR
 39         GBP
 40         RMB
 41     )
 42
 43     symbol := [...]string{USD: "$", EUR: "€", GBP: "£", RMB: "¥"}
 44     for _, v := range symbol {
 45         fmt.Printf("%s\t", v)
 46     }
 47     fmt.Printf("\n")
 48 } 

运行结果如下

 

 五. 访问

数组中的元素可通过下标进行访问  

  8 func main() {
  9     arr := [3]string{"China", "America", "Japan"}
 10     fmt.Printf("%s\n", arr[0])
 11     fmt.Printf("%s\n", arr[1])
 12     fmt.Printf("%s\n", arr[2])
 13 }

运行结果如下

 

 六. 使用

1.变量

作变量使用,这个没什么好说的了。

2.修改元素的值

1) 通过下标指定元素,对指定的元素进行修改

 8 func main() {
  9     a1 := [...]int{1, 2, 3}
 10
 11     for i, _ := range a1 {
 12         a1[i] += 4
 13     }
 14
 15     fmt.Printf("%d %d %d\n", a1[0], a1[1], a1[2])
 16 }

 运行结果如下

 

2) 笔者用过的错误的修改方式,有些想当然了。

Go中基本是值语义的,即是值传递的

for循环中,v是数组中元素的一个副本,对副本的修改不会对原始元素产生影响 

  8 func main() {
  9     a1 := [...]int{1, 2, 3}
 10
 11     for _, v := range a1 {
 12         v += 4
 13     }
 14
 15     fmt.Printf("%d %d %d\n", a1[0], a1[1], a1[2])
 16 }

  运行结果如下,并未修改成功。

 

 3.比较

如果一个数组的元素类型是可比较的,那这个数组也是可比较的。

  8 func main() {
  9     a1 := [...]int{1, 2, 3}
 10     a2 := [...]int{1, 2, 4}
 11     a3 := [3]int{1, 2, 3}
 12     fmt.Printf("%t %t %t\n", a1 == a2, a1 == a3, a2 == a3)
 13 } 

运行结果如下

 若两个数组的类型不一致,则不允许进行比较

 14     a4 := [4]int{1, 2, 3, 4}
 15     fmt.Printf("%t\n", a1 == a4) 

编译时报错如下,提示无效操作

invalid operation: a1 == a4 (mismatched types [3]int and [4]int)

 

4.作函数参数

Go中,数组是值传递的。一般是传递一个数组的指针,这样有两个好处,一是对于较大的数组,效率较高; 二是可以对原数组进行修改。下面示例两种传参方式

1) 值传递,在被调用函数 modifyArrayElement 中,通过打印结果可以看到是修改成功了,但是这只是对传入的数组的副本进行了修改,对原始数组并未产生影响。

  8 func modifyArrayElement(array [5]int) {
  9     array[0] += 10
 10     array[1] += 10
 11     array[2] += 10
 12     array[3] += 10
 13     array[4] += 10
 14
 15     fmt.Println("...in function...")
 16     for _, v := range array {
 17         fmt.Println(v)
 18     }
 19     fmt.Println("...in function...")
 20 }
 21
 22 func main() {
 23     a1 := [...]int{1, 2, 3, 4, 5}
 24     fmt.Println(a1)
 25
 26     modifyArrayElement(a1)
 27     fmt.Println(a1)
 28 }

运行结果如下

 

 2) 指针传递,在被调用函数 modifyArrayElement 的参数中,传入的是长度为5的数组的指针,通过指针可以对原数组进行修改。代码第9行和第10行array前的解引用符号"*"可以省略,可进行隐式转化。

  8 func modifyArrayElement(array *[5]int) {
  9     for i, _ := range *array {
 10         (*array)[i] += 10
 11     }
 12 }
 13
 14 func main() {
 15     a1 := [...]int{1, 2, 3, 4, 5}
 16     fmt.Println(a1)
 17
 18     modifyArrayElement(&a1)
 19     fmt.Println(a1)
 20 }

 运行结果如下

 

5.赋值

可以将一个数组赋值给另一个数组

1) 将数组b赋值给数组a

  8 func main() {
  9     a := [...]int{1, 2, 3}
 10     fmt.Println(a)
 11     b := [3]int{4, 5, 6}
 12
 13     a = b
 14     fmt.Println(a)
 15 }
 16

运行结果如下

2) 通过清零函数zero将传入的数组清零,对传入的数组指针进行解引用,然后对数组进行赋值,完成清零操作。

  8 func zero(array *[5]int) {
  9     *array = [5]int{}
 10 }
 11
 12 func main() {
 13     a := [...]int{1, 2, 3, 4, 5}
 14     fmt.Println(a)
 15
 16     zero(&a)
 17     fmt.Println(a)
 18 }

运行结果如下

 

4.与slice结合使用

具体参考slice一文

 

七. 注意

1) 适用场景

适用于固定长度的序列,如使用SHA256加密散列生成的摘要,其长度为256位,即[32]byte。

2) 越界

在访问或修改数组中的元素时,注意越界的问题

示例代码

  8 func main() {
  9     a := [...]int{1, 2, 3, 4, 5}
 10
 11     fmt.Println(a)
 12     fmt.Println(a[5])
 13 }

编译时,提示无效的数组索引5

 

 八.疑问

数组中的元素可以是哪些类型?

1) 基本类型

2) 数组类型

  8 func main() {
  9     // element type: int
 10     a1 := [...]int{1, 2, 3, 4, 5}
 11     a11 := [...]int{11, 22, 33, 44, 55}
 12     a111 := [...]int{11, 22, 33, 44, 55}
 13
 14     // element type: string
 15     a2 := [...]string{"aa", "bb", "cc", "dd", "ee"}
 16
 17     // element type: bool
 18     a3 := [5]bool{true, false, false, false, false}
 19
 20     // element type: array
 21     a4 := [3][5]int{a1, a11}
 22
 23     fmt.Println(a1)
 24     fmt.Println(a11)
 25     fmt.Println(a111)
 26
 27     fmt.Println("----------")
 28     fmt.Println(a2)
 29     fmt.Println(a3)
 30     fmt.Println(a4)
 31 }

运行结果如下

 

 其它类型待完善 

posted @ 2021-12-18 22:51  bruce628  阅读(40)  评论(0编辑  收藏  举报