《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 }

运行结果如下

其它类型待完善 

《Go程序设计语言》学习笔记之数组的更多相关文章

  1. c语言学习笔记 函数数组传递笔记

    今天学习c语言的一个小例子,果然还是陷入了php的编程习惯里,这里记录一下. #include <stdio.h> //例子很简单,就是编写一个函数把传递进来的数组里的值都赋值为1而已 / ...

  2. C语言学习笔记 (007) - 数组指针和通过指针引用数组元素的方法总结

    1.数组指针:即指向数组的指针 那么, 如何声明一个数组指针呢? ]; /*括号是必须写的,不然就是指针数组:10是数组的大小*/ 拓展:有指针类型元素的数组称为指针数组. 2.通过指针引用数组元素的 ...

  3. C语言学习笔记 (004) - 数组名和数组首地址(转)

    一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址.指针变量既然可以指向变量,当然也可以指向数组和数组元素(把数据起始地址或某一元素的地址放到一个指针变量中) ...

  4. C程序设计语言学习笔记

    在Windows下运行C语言程序 Windows下的编程工具使用 VC 6.0,下面讲解如何在VC 6.0下运行上节的"Hello, world"程序. 1) 新建Win32 Co ...

  5. Go语言学习笔记(4)——数组和切片

    1 数组的特点: 长度固定.元素数据类型相同.下标从0开始 1.1 声明和初始化: var array_name [size] type         var arr1 [10] float32   ...

  6. C语言学习笔记之数组与指针的关系

    首先,大家先需知道一个关于基类型的概念 基类型:组成一个新类型的基础类型 这句话是什么意思呢?举个例子: int a[3] = {1,2,3}; 上面是由三个int类型的数组成一个新的类型也就是数组, ...

  7. go语言学习笔记之数组

    package main import ( "fmt" ) func main() { // Declare arrays var x[5] int //Assign value ...

  8. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  9. Go语言学习笔记八: 数组

    Go语言学习笔记八: 数组 数组地球人都知道.所以只说说Go语言的特殊(奇葩)写法. 我一直在想一个人参与了两种语言的设计,但是最后两种语言的语法差异这么大.这是自己否定自己么,为什么不与之前统一一下 ...

  10. PHP学习笔记之数组篇

    摘要:其实PHP中的数组和JavaScript中的数组很相似,就是一系列键值对的集合.... 转载请注明来源:PHP学习笔记之数组篇   一.如何定义数组:在PHP中创建数组主要有两种方式,下面就让我 ...

随机推荐

  1. NC20545 [HEOI2012]采花

    题目链接 题目 题目描述 萧芸斓是Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花. 花园足够大,容纳了 \(n\) 朵花,花有 \(c\) 种颜色(用整 ...

  2. PC端应用程序自动化测试——pywinauto、pywin32、pyautogui

    1 前言 PC 端自动化测试使用到的 python 模块主要有 pywinauto.win32gui.pyautogui,主要功能如下: pywinauto:主要使用到 Application 类,用 ...

  3. SpringCloud Ribbon负载均衡服务调用实战

    介绍 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具. 主要功能是提供客户端的软件负载均衡算法和服务调用.Ribbon客户端组件提供一系列完善 ...

  4. D. Required Length

    D. Required Length 题意:给你一个长度n,一个数x,x每个后续状态可以由前一个状态乘以前一个状态的某一位上的数字得到,问最少多少步,能把x变成一个n位数.如果不能变成n位数,输出-1 ...

  5. spring事务的传播

    目录 事务的传播行为类型 注意事项 关于事务的传播,我们先确定一个场景:方法A调用方法B,方法A可能存在事务,也可能不存在事务,我们这里重点关注方法B上定义的事务传播行为,以及方法B中出现异常时,方法 ...

  6. P4141 消失之物题解(写给每一位与我一样的新手玩家)

    消失之物 传送门: P4141 消失之物 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 暴力稳了 但是 hack tle了 这时候我们要想办法优化 这是一个回退背包问题 首先 ...

  7. QT - Day 4

    1  界面布局 实现登录窗口 利用布局方式,给窗口类化 选取Widget进行布局,水平布局,垂直布局,栅格布局 给用户名.密码.登录.退出按钮进行布局 默认窗口和控件之间有9间隙,可以调整layout ...

  8. 字符串,format格式化及列表的相关进阶操作---day07

    1.字符串相关操作 (1)字符串的拼接 (2)字符串的重复 (3)字符串跨行拼接 (4)字符串的索引 (5)字符串的切片:[开始索引:结束索引:步长] 2.字符串的格式化format (1)顺序传参 ...

  9. React之父组件向子组件传值

    class Parent extends React.Component{ constructor(){ super(); this.state={co:"red"} } rend ...

  10. web模块化

    CommonJS-----是一种后端js规范,是nodejs遵循的一种编写js模块的规范引入模块-------require('模块路径')定义模块 ------ exports.模块名= funct ...