1,数组的特性
数组是线性表结构,从而内存空间是连续的且有着相同类型的数据。
正是由于是线性结构的特性才支持随机访问,时间复杂度为o(1)。
通过公式a[i]_address = base_address + i * data_type_size计算得到数组元素地址。
但是其插入、删除操作比较低效,因为会涉及到数据的迁移问题。以上就是数组的基本特性,下面我们看一下golang中数组相关知识。
2,声明及初始化
2.1,直接声明不显示初始化
var arr []type
数组声明之后编译器会做初始化操作,用数组值类型的零值进行初始化。
2.2,用一组值初始化数组
var arr [3]type = []type{1, 2, 3}
2.3,在数组字面值中,如果在数组的长度位置出现的是“...”省略号,则表示数组的长度是根据初始值的长度确定的。
q := [...]int{1, 2, 3}
2.4,制定索引和对应值列表的方式初始化
type Color int
const (
YELLOW = iota
RED
GREEN
BLUE
)
symbol := [...]string{YELLOW: "#FFFF00", RED: "#FF0000", GREEN: "#008000", BLUE: "#0000FF"}
2.5,定义数组大于0的索引初始化,其它元素都是用0自动初始化。
r := [...]int{99: -1}
此r数组的元素值是99个0,最后一位是-1
3,数组比较
如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,这时候我们可以直接通过==比较运算符来比较两个数组,只有当两个 数组的所有元素都是相等的时候 数组才是相等的。
数组长度是数组类型的组成部分,[1]int与[2]int是2种不同的数组类型。
数组长度必须是常量表达式,因为数组的长度需要在编译阶段确定。
4,数组越界
- 数组的长度是固定的,不能访问数组下标合法范围之外的值。
- 访问非法下标则触发访问越界,会panic。
5,类型、容量、长度
- 数组是值类型,顾名思义就是数组里面的数据不是数组地址。
- 数组的长度可以通过len(arr)来获取到。
- 数组的容量可以通过cap(arr)来获取到。
6,打印
fmt.Printf("%p", &arr) 打印数组首地址。
fmt.Printf("%p", &arr[1])打印数组非首地址。
7,函数参数为数组
一般函数的参数传递很少用到数组传参,因为数组传参是值传递,需要拷贝整个数组,需要更改数组中的值需要传数组地址。
8,数组的内存布局
由于数组是连续的内存空间,为了直观的感受一下我把数组内存地址指向的数据打印出来。注意由于是int是占4个字节,我的系统是64位所以int数组低4位存储值且不足的字节用0填充,而高4位的0的目的是字节对齐。见下图1,图2:
9,数组遍历
- 通过range进行循环遍历。
- 通过len(arr) + for循环遍历。
10,数组指针
- 只的是数组元素可以是指针类型,例如:
arr := [3]*int{new(int), new(int)}
11,二维数组
package main
import "fmt"
var arr = [4][2]int{{1, 2}, {3, 4}, {5, 6}, {7, 8}}
func main() {
fmt.Println(arr[2][1])
}
以上代码声明了4行2列的数组,数组元素的访问是通过数组的下标来实现的。那数组的元素在真实内存中是按什么顺序排列的呢,看下图3:
我们可以看到数组的值排序是将行依次拼接而成。
12,总结
数组是golang中比较基本的数据类型,做为一个容器来为slice提供存储服务,但是在实际应用中直接用它不是很多,用slice则用的很多因为它灵活。下篇讲解golang中slice的使用。
有疑问加站长微信联系(非本文作者)