写在前面


  • 嗯,学习GO,所以有了这篇文章
  • 博文内容为《GO语言实战》读书笔记之一
  • 主要涉及数组相关知识

世上除了爹娘,再没有人是理所应当对你好的。 ——烽火戏诸侯《剑来》


数组的内部实现和基础功能

数组在GO里是切片映射基础数据结构,学过其他语言的小伙伴对数组应该都不陌生。基本上所有的语言都会有数组的概念。

数组(Array)是一种线性数据结构。它用一组连续内存空间,来存储一组具有相同类型的数据

内部实现

Go语言里,数组是一个长度固定的数据类型,用于存储一段具有相同的类型的元素的连续块。数组存储的类型可以是内置类型,如整型或者字符串,也可以是某种结构类型

数组因为其占用的内存是连续分配的。CPU能把正在使用的数据缓存更久的时间。而且内存连续很容易计算索引,可以快速迭代数组里的所有元素。数组的类型信息可以提供每次访问一个元素时需要在内存中移动的距离。

关于上面这句话我个人理解:

  • 数组结构上内存连续分配,所以很容易的计算索引(元素的相对地址),等差数列,同时内存连续,可以很好的使用CUP的缓存,当CPU访问首地址时,会自动的从内存中加载当前数组其他元素到CUP Cache,加载多少由CPU Cache Line决定,所以CPU能把正在使用的数据缓存更久的时间。当内存不连续时,就无法读到 CPU Cache,只能重复的从内存读取数据元素,也就不能充分利用到了CPU Cache的特性
  • 通过索引可以快速的迭代数组元素,如果用a代表数组的首地址,a[0]就是偏移量为0的位置,也就是首地址,a[k]就表示偏移量ktype_size的位置,所以计算a[k]的内存地址只需要用这个公式a[k]_address = base_address + k * type_size,所以说可以通过索引确认内存地址快速迭代,理论上时间复制度为常量级。

声明和初始化

声明数组时需要指定内部存储的数据的类型,以及需要存储的元素的数量

  • 声明一个数组,并设置为零值
var arrays [5]int
  • 使用数组字面量声明数组
arrays := [5]int{10,12,13}
  • Go 自动计算声明数组的长度
array := [...]int{10, 20,30, 40, 50}
  • 声明数组并指定特定元素的值,用具体值初始化索引为12的元素
array := [5]int{1: 10, 2: 20}

使用数组

内存布局是连续的,所以数组是效率很高的数据结构,在访问数组里任意元素的时候,使用[]运算符

  • 访问数组元素
//声明一个包含 5 个元素的整型数组
array := [5]int{10, 20, 30, 40, 50}
// 修改索引为 2 的元素的值
array[2] = 35

声明一个所有元素都是指针的数组。使用*运算符就可以访问元素指针所指向的值

  • 访问指针数组的元素
// 声明包含 5 个元素的指向整数的数组
// 用整型指针初始化索引为 0 和 1 的数组元素
array := [5]*int{0: new(int), 1: new(int)}
// 为索引为 0 和 1 的元素赋值
*array[0] = 10
*array[1] = 20

Go 语言里,数组是一个值。这意味着数组可以用在赋值操作中。变量名代表整个数组,同样类型的数组可以赋值给另一个数组

// 声明第一个包含 5 个元素的字符串数组
var array1 [5]string
// 声明第二个包含 5 个元素的字符串数组
// 用颜色初始化数组
array2 := [5]string{"Red", "Blue", "Green", "Yellow", "Pink"}
// 把 array2 的值复制到 array1
array1 = array2
  • 编译器会阻止类型不同的数组互相赋值
package mainimport "fmt"func main() {fmt.Println("你好,世界")// 声明第一个包含 4 个元素的字符串数组var array1 [4]string// 声明第二个包含 5 个元素的字符串数组// 使用颜色初始化数组array2 := [5]string{"Red", "Blue", "Green", "Yellow", "Pink"}// 将 array2 复制给 array1array1 = array2
}

go vet检查

┌──[root@liruilongs.github.io]-[/usr/local/go/src/demo]
└─$go fmt array.go
array.go
┌──[root@liruilongs.github.io]-[/usr/local/go/src/demo]
└─$vim array.go
┌──[root@liruilongs.github.io]-[/usr/local/go/src/demo]
└─$go vet array.go
# command-line-arguments
vet: ./array.go:15:11: cannot use array2 (variable of type [5]string) as [4]string value in assignment
┌──[root@liruilongs.github.io]-[/usr/local/go/src/demo]
└─$

多维数组

数组本身只有一个维度,不过可以组合多个数组创建多维数组。多维数组很容易管理具有父子关系的数据或者与坐标系相关联的数据

  • 声明二维数组
// 声明一个二维整型数组,两个维度分别存储 4 个元素和 2 个元素
var array [4][2]int
// 使用数组字面量来声明并初始化一个二维整型数组
array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 声明并初始化外层数组中索引为 1 个和 3 的元素
array := [4][2]int{1: {20, 21}, 3: {40, 41}}
// 声明并初始化外层数组和内层数组的单个元素
array := [4][2]int{1: {0: 20}, 3: {1: 41}}
  • 访问二维数组的元素
// 声明一个 2×2 的二维整型数组
var array [2][2]int
// 设置每个元素的整型值
array[0][0] = 10

只要类型一致,就可以将多维数组互相赋值

// 声明两个不同的二维整型数组
var array1 [2][2]int
var array2 [2][2]int
// 为每个元素赋值
array2[0][0] = 10
array2[0][1] = 20
array2[1][0] = 30
array2[1][1] = 40
  • 同样类型的多维数组赋值
// 将 array2 的值复制给 array1
array1 = array2
  • 使用索引为多维数组赋值
// 将 array1 的索引为 1 的维度复制到一个同类型的新数组里
var array3 [2]int = array1[1]
// 将外层数组的索引为 1、内层数组的索引为 0 的整型值复制到新的整型变量里
var value int = array1[1][0]

在函数间传递数组

根据内存和性能来看,在函数间传递数组是一个开销很大的操作。在函数之间传递变量时,总是以值的方式传递的。如果这个变量是一个数组,意味着整个数组,不管有多长,都会完整复制,并传递给函数。

  • 使用值传递,在函数间传递大数组
// 声明一个需要 8 MB 的数组,创建一个包含 100 万个 int 类型元素的数组
var array [1e6]int
// 将数组传递给函数 foo
foo(array)
// 函数 foo 接受一个 100 万个整型值的数组
func foo(array [1e6]int) {...
}

每次函数foo被调用时,必须在栈上分配8 MB的内存

还有一种更好且更有效的方法来处理这个操作。可以只传入指向数组的指针,这样只需要复制8字节的数据而不是8 MB 的内存数据到栈上

  • 使用指针在函数间传递大数组
// 分配一个需要 8 MB 的数组
var array [1e6]int
// 将数组的地址传递给函数 foo
foo(&array)
// 函数 foo 接受一个指向 100 万个整型值的数组的指针
func foo(array *[1e6]int) {...
}

将数组的地址传入函数,只需要在栈上分配 8 字节的内存给指针就可以.

Go语言实战之数组的内部实现和基础功能相关推荐

  1. 《智能对话机器人开发实战20讲》--学习笔记--AIML基础功能拓展-与互联网的集成

    一.学习笔记 环境要求: aiml bs4 语料库: tuling.aiml search_web.aiml <that>WHICH SEARCH ENGINE WOULD YOU LIK ...

  2. Jemter+Badboy实战经验一(Badboy录制及基础功能)

    1. 使用工具: Apache Jemeter:http://jmeter.apache.org/download_jmeter.cgi (免费官网下载地址) BadBoy:   http://www ...

  3. R语言 tidyverse系列学习笔记(系列1)基础功能的代码实现

    tidyverse 译 "洁净的宇宙" => "极乐净土" 以 iris 鸢尾花数据集为例 ** 查看数据集** ** 查看维度dimention** d ...

  4. R plot图片背景设置为透明_R语言实战 牛国庆

    [toc] 第一章 1.3.2 R中帮助函数 R中用于管理R工作空间的函数 函数setwd()不会自动创建一个不存在的目录.如果必要的话,可以使用函数dir.create()来创建新目录,然后使用se ...

  5. Go语言实战读书笔记

    2019独角兽企业重金招聘Python工程师标准>>> Go语言实战读书笔记 第二章 通道(channel).映射(map)和切片(slice)是引用类型.引用类型的对象需要使用ma ...

  6. r语言electricity数据集_R语言实战学习

    <R语言实战>中文电子版 提取码:lx35 已经学习打卡R语言22天了,可以说是初窥真容--基本了解R的数据和函数:作为程序语言,就是要多练习,多领悟,在实战中发现问题并解决问题. 所以, ...

  7. go int 转切片_一文掌握GO语言实战技能(二)

    Go 数组 Go 切片 Go 变量和内存地址 Go Map 类型 Go 面向对象编程 Go 方法的定义 GO 数组 数组是同一类型的元素集合.Go中的数组下标从0开始,因此长度为n的数组下标范围是[0 ...

  8. go语言实战_字节跳动年薪50W抢Go开发人才,你还在问该不该学?

    字节跳动近期招聘Go开发工程师,给出年薪50W的薪资水平,还有额外期权,免费三餐等,随着这几年Go语言在一线厂商兴起,各大互联网开始抢夺Go开发人才, 在最近10年,运维自动化和云平台建设等领域是Go ...

  9. r语言 新增一列数字类型_R语言实战之R语言基础语法精讲(一)

    R是用于统计分析.绘图的语言和操作环境.R是属于GNU系统的一个自由.免费.源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具.在学习R数据科学之前,我们首先要对R语言的基础语法有一个良好的了 ...

最新文章

  1. hadoop面试记录(一)
  2. CButtonST的用法详解!
  3. linux c之用fopen、fputs、fgets、 fseek来对文件进行写、替换、读
  4. Java Servlet 过滤器与 springmvc 拦截器的区别?
  5. Python生成exe可执行文件的两种方法(py2exe和pyinstaller)
  6. 将一个字符串进行反转。将字符串中指定部分进行反转
  7. Ubuntu21.04 安装 VLC视频播放器
  8. 手把手教你SpringBoot+MyBatis+Shiro 搭建项目框架
  9. android 安卓editext默认弹出英文输入法,只能输入英文与数字
  10. Wine——在Linux上运行Windows软件
  11. Spring MVC+Stomp+Security+H2 Jetty 1
  12. SpringBoot整合freemarker模板导出word文件
  13. RabbitMQ使用教程(超详细)
  14. 好领导,本来应是挖渠人
  15. 中国移动SP短信网关接入平台
  16. QT开发代码格式化设置
  17. 导入下载excel(还有excel多个sheet)和txt文本的方法
  18. LaTeX复选框实现
  19. 政府OA办公系统实施时需要关注的五个环节
  20. 阅读ConcurrentHashMap源码的一些记录

热门文章

  1. long 型应该加上 l或者L
  2. 《我的极品媳妇》方志强 王亚欣 小说读后感
  3. 鸿蒙OS内核分析|解读鸿蒙源码
  4. 2021年中国旅游人次、箱包销售收入及利润总额分析[图]
  5. 磐石云服务器_超牛的盘石云服务器平台
  6. Python-七段数码管的绘制实例
  7. Matlab学习手记——非线性拟合方法:压缩因子粒子群算法
  8. win10系统升级一段时间后,内存占用过高
  9. 激活windows系列地址
  10. uniapp使用picker