Go by Example-图解数组
基本概念
1、数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型。
2、在 Go 中因为数组的内存布局是连续的,所以可以通过索引(位置)来读取(或者修改),索引是从 0 开始,第一个元素索引为 0,第二个索引为 1,这样以此类推。
3、声明数组时需要指定数据的类型,以及数组的长度。
var array [6] int
// 声明的规则:var + 变量名 + 类型
Go 和 Python 不一样,在声明变量的时候依次是 “var”、变量名、变量类型。这里我们声明一个包含 6 个元素的 int 类型的数组,这个数组在初始化的时候会被设置为该类型的零值。
数组创建
- 声明一个长度为 5 的 int 类型的空数组。
var arr=[5] int {}
fmt.Println (arr)
因为没有赋值,所以会打印其零值也就是 5 个 0
上面的过程我们可以通过一个图来表示:

图中 5 个连续的蓝色格子表示数组占用内存是连续分配的。
每一个格子表示数组的一个元素,每个元素的类型相同,这里的例子全是整数的,我们可以通过数组的下标访问数组中对应位置的元素。
当数组初始化的时候,数组每个元素都会初始化为其零值,其他语言习惯叫默认值。
每个数据类型的零值也是不一样的,这里就拿我们这个例子,因为每个元素都是 int 类型所以其零值为 0。
- 声明一个长度为 6 的 int 类型数组并赋值
array:= [6] int {5,10, 20, 30, 40, 50}
- 如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小
arr1:=[...] int {1, 2, 3, 4, 5}
fmt.Println (arr1)
需要注意不指定数组大小的时候使用 ..., 如果不写东西就是切片了。
4. 还可以在定义的时候根据下标进行赋值
array:=[5] int {0:2,3:2}
定义了一个长度为 5 的 int 类型数组,: 前面的 0,3 表示当前下标,: 后面是要赋的值

通过演示图可以得知,下标 0 和 3 的元素赋值了,其他没有赋值的元素仍然是 0。
- 如果数组下标太大,编译会提示下标越界
array:=[4] int {0:2,3:2}
array [6] =4
fmt.Println (array1)
这里我们定义了数组长度为 4,其下标最大是 3, 这是要给下标第 6 个元素赋值,编译不通过。
数组复制
在 Go 中具有相同类型的,相同个数的数组,可以相互直接进行赋值。
// 复制
array1:=[4] int {0:2,3:2}
array2:=[4] int {}
array3:=[4] int {3,4,5,7}
array2 =array1 // 具有相同类型的,相同个数的数组,可以相互直接进行赋值
array3 =array2
fmt.Println (array2)
fmt.Println (array3) // 可以看到 array3 被 array2 完全覆盖
数组遍历
Go 语言一种独有的结构 for...range,可以用来遍历访问数组的元素,也可以遍历 map。这里先说数组
for ix, value := range array01 {
...
}
第一个返回值 ix 是数组的索引,第二个是在该索引位置的值;他们都是仅在 for 循环内部可见的局部变量。value 只是 array01 某个索引位置的值的一个拷贝,不能用来修改 array01 该索引位置的值。如下面的例子
package main
import "fmt"
var array [6] int
func main () {
array [1] =7 #根据下标给数组赋值,下标 0 开始。
for k,v:=range array {
fmt.Printf ("% d:% d \n",k,v)
}
}
输出结果
0:0
1:7
2:0
3:0
4:0
5:0
上面的代码我们只对列表第二个元素进行了赋值,可以看出其他位置默认零值为 0。
有时候,在一开始就想好了给数组赋几个值,赋什么值,这个时候我们可以使用下面的方式定义。
不过上面的代码有个限制就是,一旦长度设定了,后面就能在改变了。
所以一般情况下更建议使用后面文章提到的切片。
数组指针和指针数组
在说这个问题前,首先需要了解什么是 指针。
指针就是一个变量,它存储的数据不仅仅是一个普通的值,如简单的整数或字符串,而是另一个变量的内存地址。
一个指针变量可以指向任何一个值的内存地址它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,可以声明指针指向任何类型的值来表明它的原始性或结构性;你可以在指针类型前面加上 * 号(前缀)来获取指针所指向的内容,这里的 * 号是一个类型更改器。使用一个指针引用一个值被称为间接引用。
当一个指针被定义后没有分配到任何变量时,它的零值为 nil。
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go 语言中使用 & 作符放在变量前面对变量进行 “取地址” 操作。
了解了什么是指针了,下面让我们先看什么是数组指针。
简单说,数组指针其实就是 “数组的指针” 的简写,指针指向的数组的内存地址。
其形式为
var arr = [...] int {5:2}
// 数组指针
var ptf *[6] int = &arr // 和数组数量必须相等
ptf [2]=3
ptf [1]=7
fmt.Println (ptf)
然后看指针数组,同样的可以理解为指针数组的全称是 “指针类型的数组”。
func main () {
array1 := [5]*int {0: new (int), 1: new (int)}
*array1 [0] = 10
*array1 [1] = 20
array1 [2] = new (int) // 因为定义的时候没有给下标 2 的元素分配空间,所以这里是分配一块内存
*array1 [2] = 30 // 如果没有上一步这步会报错
fmt.Println (array1)
}
打印可以发现
[0xc000016038 0xc000016040]
所谓的指针数组就是,数组的元素全是指针组成的。
上面 array1 数组操作用图表示的话

此时的数组内每个元素存的实际上是指向 new 创建对应类型的指针,这里是 int 类型的指针。
官方对 new 的描述是:内建函数 new 用来分配内存,它的第一个参数是一个类型,不是一个值,它的返回值是一个指向新分配类型零值的指针。
需要注意的一点是只有给元素分配内存空间了才能对其进行操作,如果元素是 nil,直接对元素赋值的话就会出现错误,就像上面的 array1[2]。
这个数组的元素是指针类型的,存放的是指向整数的地址的指针。
指针数组的复制
下面我们看看如果对指针数组进行复制操作,内存中变化什么样呢。
func main () {
array1 := [5]*int {0: new (int), 1: new (int)}
// 为索引为 0 和 1 的元素赋值
*array1 [0] = 10
*array1 [1] = 20
array2 := array1
*array1 [0] =80
fmt.Println (array2==array1)
}

通过图片可以得知,复制数组指针,只会复制指针的值,而不会复制指针所指向的值。
所以修改 array1 的指针指向的地址时,array2 也会跟着变,所以 array1 和 array2 相等。
后记
在函数间传递数组,如果数组过大将造成巨大的开销,所以一般会将其转换为指针,这里为什么没有单独的拿出讲解,就是因为不推荐给函数传入数组。而是使用抽象度更高的切片。
更多内容关注公众号:python学习开发,添加微信:italocxa,回复加群:关键词Python、Go,需要哪个回复哪个即可。
Go by Example-图解数组的更多相关文章
- Java - 数组详解(图解数组的基本操作)
目录 什么是数组 数组的定义和内存分配 数组的赋值和访问 数组的注意事项 数组的内存图解 数组的插入 数组的删除 数组的扩容 数组的反转 首先 什么是数组 数组是一组地址连续.长度固定的具有相同类型的 ...
- 05 方法与数组笔记【JAVA】
---恢复内容开始--- 1:方法(掌握) (1)方法:就是完成特定功能的代码块. 注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法. (2)格式: 修饰符 返回值类型 方法名(参数类 ...
- Java Day 04
01 语句 循环结构 嵌套 列的递减 1-5 2-5 3-5// 1-5 1-4 1-3 转义字符 \n 回车 \t 制表符 \b 退格 \r 按下回车键 windows 回车符由 \r \n 组成 ...
- Junit 注解 类加载器 .动态代理 jdbc 连接池 DButils 事务 Arraylist Linklist hashset 异常 哈希表的数据结构,存储过程 Map Object String Stringbufere File类 文件过滤器_原理分析 flush方法和close方法 序列号冲突问题
Junit 注解 3).其它注意事项: 1).@Test运行的方法,不能有形参: 2).@Test运行的方法,不能有返回值: 3).@Test运行的方法,不能是静态方法: 4).在一个类中,可以同时定 ...
- JavaBasic_05
方法 简述:实现特定功能的代码块 格式 修饰符: 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…){ 函数体; return 返回值;} 方法格式 ...
- 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案
之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...
- js数组操作-最佳图解
js数组操作-最佳图解
- 06-01 Java 二维数组格式、二维数组内存图解、二维数组操作
二维数组格式1 /* 二维数组:就是元素为一维数组的一个数组. 格式1: 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. n:表示每一个一维数组的 ...
- Java中数组在内存中的图解
Java中的数组在内存中的图解,其实对于数组,还是比较熟悉的,平时用的也是很多的,在看数据结构与算法的极客时间专栏,最常用的10个数据结构:数组.链表.栈.队列.散列表.二叉树.堆.跳表.图.Trie ...
- 图解c/c++多级指针与“多维”数组
声明:本文为原创博文,如有转载,请注明出处.若本文有编辑错误.概念错误或者逻辑错误,请予以指正,谢谢. 指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的.其中,多级指针与“多维”数组更 ...
随机推荐
- VBA switch语句
当用户想要根据Expression的值执行一组语句时,使用Switch Case语句. 每个值被称为一个”情况”,并根据每种情况变量接通测试.如果测试表达式与用户指定的任何Case不匹配,则执行Cas ...
- 【小知识点】js无需刷新在url地址添加参数
今天后端同事找我,问我一个关于js无需刷新在url地址添加参数的方法. 然后我百度啊,终于在一篇文章找到了办法,非常简单的一句代码. window.history.pushState({}, 0, w ...
- ABAP-会计凭证替代字段GB01设置
1.GB01表字段设置 SM30:VWTYGB01 找到需要替代的字段,设置bexclude勾选为空 2.运行程序 RGUGBR00 激活
- FICO-财务凭证验证及替代
转载:https://wenku.baidu.com/view/9e2dae57d15abe23492f4d39.html?sxts=1561613818537 https://wenku.baidu ...
- Redis 从入门到放弃
Redis 从入门到放弃 http://www.iocoder.cn/Fight/Redis-went-from-getting-started-to-quitting/
- linux网络编程之posix条件变量
今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...
- linux网络编程之socket编程(十六)
继续学习socket编程,今天的内容会有些难以理解,一步步来分解,也就不难了,正入正题: 实际上sockpair有点像之前linux系统编程中学习的pipe匿名管道,匿名管道它是半双工的,只能用于亲缘 ...
- 【BZOJ3691】游行 最小可相交路径覆盖转化
因为C是不断变化的而且C是和点权相关和边权无关 所以我们可以MCMF但是MCMF的时候不能与C相关 再分析问题 我们可以认为每条路径S->T只覆盖T这个终点 因为题目中说了如果Si != Ti ...
- python数据类型:dict(字典)
一.字典的简单介绍 字典(dict)是python中唯一的一个映射类型.他是以{}括起来的键值对组成. 语法: {key1:value1,key2:value2......} 注意:key必须是不可变 ...
- springboot的入门
SpringBoot SpringBoot是SpringMVC的升级版,简化配置,很可能成为下一代的框架 1.新建项目 怎么创建springBoot项目呢? 创建步骤复杂一点点 New Project ...