基本概念
1. 数组是一组具有相同唯一类型的编号且固定长度的数据项序列,可以是任何原始类型,例如整数、字符串或自定义类型。
2.在Go中,由于数组的内存布局是连续的,因此可以通过索引(位置)来读取(或修改)。 索引从0开始,第一个元素索引为0,第二个元素索引为1。以此类推。
3、声明数组时,需要指定数据类型和数组长度。
var array [6] int
// 声明的规则:var + 变量名 + 类型
围棋则不同。 声明变量时,后面跟着“var”、变量名和变量类型。 在这里,我们声明了一个包含 6 个 int 类型元素的数组,该数组在初始化时将被设置为该类型的零值。
数组创建
声明一个长度为 5 的 int 类型的空数组。
var arr=[5] int {}
fmt.Println (arr)
因为没有赋值,所以会打印它的零值,即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)
需要注意的是,...是在不指定数组大小的情况下使用的。 如果你不写任何东西,它就是一个切片。
定义时也可以根据下标赋值
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。这是给下标的第六个元素赋值,编译失败。
数组复制
在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 只是索引位置处的值的副本,不能用于修改该索引位置处的值。如下例
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]
所谓指针数组,就是数组的元素全部由指针组成。
如果将上面的数组运算用一个图来表示
此时数组中的每个元素实际上存储了一个指向new创建的对应类型的指针,这里是一个int类型的指针。
new的官方描述是:内置函数new用于分配内存,它的第一个参数是一个类型,而不是一个值,它的返回值是一个指向新分配的类型的零值的指针。
需要注意的一点是,只有在分配内存空间后才能操作元素。 如果元素为nil,直接给元素赋值就会出错,就像上面的[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)
}
从图中可以看出,复制数组指针只会复制指针的值,而不会复制指针指向的值。
因此,修改后的指针指向的地址也会相应改变,所以和相等。后记
在函数之间传递数组如果数组太大会造成巨大的开销,所以一般会转为指针。 这里为什么不单独解释是因为不建议将数组传递给函数。 相反,使用具有更高抽象级别的切片。
因为我也在学习,如果有不足的地方,欢迎大家指出。