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++编程中非常重要的元素,同时也是较难以理解的.其中,多级指针与“多维”数组更 ...
随机推荐
- 50个Sql语句实战
/* 说明:以下五十个语句都按照测试数据进行过测试,最好每次只单独运行一个语句. 问题及描述:--1.学生表Student(S#,Sname,Sage,Ssex) --S# 学生编号,Sname 学生 ...
- AM--消息队列
kafka rocketMq零拷贝对比 https://cloud.tencent.com/developer/news/333695 还有Linux目录下的基本原理 RocketMQ Kafka C ...
- MVC-路由(Route)
1.启用路由前的准备工作 Global.asax.cs中注册路由 public class MvcApplication : System.Web.HttpApplication { protecte ...
- Mysql之表的查询
一.单表的查询 首先让我们先熟悉一下mysql语句在查询操作时执行的顺序: (1)from (2) on (3) join (4) where (5)group by (6) avg,sum ...
- 异常-No suppression parameter found for notification
1 详细异常 Command Start is not currently available for execution. 关闭 kafka gateway 无法启动 java.lang.NullP ...
- 【python cookbook】找出序列中出现次数最多的元素
问题 <Python Cookbook>中有这么一个问题,给定一个序列,找出该序列出现次数最多的元素.例如: words = [ 'look', 'into', 'my', 'eyes', ...
- mr-robot靶机练习
在业余时间进行的靶机练习,也是根据网上的大牛做下来的,重复造轮子吧,但是个人感觉还是即使是造轮子也是需要自己动手呀,毕竟每个人做的过程中遇到的问题是不一样的,这样既可以帮助别人也能锻炼自己.希望可以帮 ...
- Linux下常用mysql命令【2】
1.开启和关闭 1.1.开启 systemctl start mysqld 1.2.关闭 systemctl stop mysqld 1.3.重启 systemctl restart mysqld 回 ...
- 创建虚拟目录 http://localhost:1001/ 失败,错误: 无法创建网站
使用vs2015打开一个vs2008项目报错了. 最后网上找到的解决方案, 1,打开编辑xxx.csproj文件: 2,找到节点ProjectExtensions注释掉: 3,重新加载就好了.
- ASP.NET六大巨头——内置对象(2)
前面讲了三个内置对象,后面来探究一下另外三个内置对象Session.Server和Cookie,Session对象就是服务器给客户端的一个编号:Server对象提供对服务器上的方法和属性的访问:coo ...