《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. NC19246 数据结构

    题目链接 题目 题目描述 qn姐姐最好了~ qn姐姐给你了一个长度为n的序列还有m次操作让你玩, 1 l r 询问区间[l,r]内的元素和 2 l r 询问区间[l,r]内的元素的平方和 3 l r ...

  2. 【Unity3D】法线贴图和凹凸映射

    1 法线贴图原理 ​ 表面着色器中介绍了使用表面着色器进行法线贴图,实现简单快捷.本文将介绍使用顶点和片元着色器实现法线贴图和凹凸映射,实现更灵活. ​ 本文完整代码资源见→法线贴图和凹凸映射. ​ ...

  3. 使用JS快速读取TXT文件

    1 前言 最近有个需求,需要使用JS快速读取外部大数据文件(60w条记录的表).笔者尝试过使用JS读取Excel文件,但是跑了十几分钟仍未出结果,后来笔者尝试将原数据保存为TXT文件,再从TXT文件中 ...

  4. 【OpenGL ES】绘制彩色三角形

    1 前言 ​ [OpenGL ES]绘制三角形 中介绍了绘制普通三角形的方法,本文将介绍绘制彩色三角形的方法. ​ 本文完整代码资源见→[OpenGL ES]绘制彩色三角形 ​ 项目目录如下: 2 案 ...

  5. Swoole从入门到入土(15)——WebSocket服务器[初步接触]

    WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.换句话说,Websocket让web可以与服务端实现长连接. 在Swoole中,通过内置的 WebSock ...

  6. form表单如何实现ajax提交

    最近在开发一个游戏网关的后台管理系统,总结了下中间碰到的一些问题. 之一就是:form表单如何实现ajax提交? 问题:在使用form表单的时候,一旦点击提交触发submit事件,一般会使得页面跳转, ...

  7. c2工具sliver 执行木马命令后会弹窗一闪而过

    向木马发出指令后, 如果是cmd命令会有一个黑窗口一闪而灭, 不利于木马隐藏, 需要将executeHandler从handlers.go拷贝到handlers_windows.go里,核心代码为 c ...

  8. 负载均衡load balancing和算法分类概要介绍

    一.负载均衡介绍 1.1 什么是负载均衡 负载均衡(load balancing) 它是计算机的一种技术,用来在计算机集群.网络连接.CPU.磁盘驱动器或其他资源中分配负载,以达到优化资源使用.最大化 ...

  9. logback 常用配置(详解)

    转自:https://blog.csdn.net/qq_36850813/article/details/83092051 官方文档参考:https://logback.qos.ch/manual/a ...

  10. Java JVM——3.运行时数据区概述及线程

    运行时数据区概述 在JVM 中的位置 内部划分 当我们通过前面的:类的加载 → 验证 → 准备 → 解析 → 初始化 这几个阶段完成后,执行引擎就会对我们的类进行使用,同时执行引擎将会使用到我们的运行 ...