数组的内部实现和基础功能
数组是切片和映射的基础数据结构
文章目录
1.内部实现
数组是一个长度固定的数据类型,用于存储一段具有相同相同类型的元素的连续块
a. 数组的存储类型可以是:内置类型、整形、字符串、数据结构类型
b. 数组是紧邻连续的数据结构,元素可以通过下标访问
注:连续占用内存的分配机制,是的数据缓存时间更久,而且内存连续很容易计算索引数组的类型信息可以提供每次访问一个元素需要在内存中移动的距离,相同的数据类型且又连续使得可以以固定的速度(快速)索引数组中的元素
2.声明和初始化
声明数组时需要指定内部存储的类型和与元素的数量(长度)
一旦声明其长度及数量不可改变(可以使:创建新更长的数组,并复制原来的数据实现数组扩容)
初始化数组时,数组的每个值都会初始化为对应类型的零值
a. 声明式数组
// 声明一个包含五个元素的数组
var array [5]int
// 输出结果:
// == array: [0 0 0 0 0]
b. 数组字面量声明数组
// 声明一个包含五个元素的数组
// 用具体的数值初始化每个元素
rain := [5]int{10, 20, 30, 40, 50}
// 输出结果:
// == rain: [10 20 30 40 50]
c. 自动声明数组的长度
// 声明一个整形数组
// 用具体的数值初始化元素
// 数组的长度由初始化值的数量决定
rain_1 := [...]int{1, 2, 3, 4, 5, 6}
// 输出结果:
// == rain_1: [1 2 3 4 5 6]
d. 声明数组并指定特定元素的数值
// 声明一个包含6个元素的整形数组
// 用具体的数值初始化1和3元素的值
rain_2 := [5]int{1:10, 3:30}
// 输出结果:
// == rain_2: [0 10 0 30 0]
3. 数组的使用
a. 修改数组内的元素
// 声明一个数组并初始化数值
rain_3 := [...]int{1, 2, 3, 4, 5}
// 修改下标为3的元素的数值
rain_3[3] = 7
// 输出结果:
// == rain_3: [1 2 3 4 5]
// == rain_3: [1 2 3 7 5]
b. 访问指针数组的元素
使用 * 可以访问元素指针所指向的数值
// 声明一个指针元素数组, 并初始化索引为2和5个元素
rain_4 := [6]*int{2:new(int), 5: new(int)}
// 修改索引为2和5的元素的数值
*rain_4[2] = 20
*rain_4[5] = 50
// 输出结果:
// == rain_4: [<nil> <nil> 0xc000066080 <nil> <nil> 0xc000066088]
c. 同类型的数组相互赋值
Go语言数组是一个值,这使得它可以可以赋值给另一个相同类型 的数组
// 声明一个5个字符串长度的数组
var rain_5 [5]string
// 声明一个5个字符串长度的数组,并初始化数值
rain_6 := [5]string{"red", "orange","yellow", "green", "blue"}
// 赋值
rain_5 = rain_6
// 输出结果:
// == rain_5: [red orange yellow green blue]
// ==rain_6: [red orange yellow green blue]
d. 相同类型的指针数组相互赋值
复制数组指针,只会复制复制指针的值,而不会复制指针所指向的值
// 创建空的指针数组
rain_7 := [3]*string
// 使用字符串指针初始化rain_8
rain_8 := [3]*string{new(string), new(string), new(string)}
// 为rain_8 赋值
*rain_8[0] = "apple"
*rain_8[1] = "banana"
*rain_8[2] = "orange"
// rain_8 赋值给 rain_7
rain_7 = rain_8
// 输出结果:
// == rain_7: [0xc0000521c0 0xc0000521d0 0xc0000521e0]
// == rain_8: [0xc0000521c0 0xc0000521d0 0xc0000521e0]
4. 多维数组
数组本身只有一个维度,但可以组合多个数组创建多维数组
a. 声明多维数组
// 整形的零值为 0
// 声明一个二维整形数组
var mist [3][2]int
// 使用字面量创建一个二维数组,并初始化
mist_1 := [3][2]int{{1,1}, {2,2}, {3, 3}}
// 声明并初始化内外层索引为2的数组
mist_2 := [3][2]int{2:{2:7}}
// 输出结果:
// == mist: [[0 0] [0 0] [0 0]]
// == msit_1: [[1 1] [2 2] [3 3]]
// == mist_2: [[0 0] [0 0] [0 7]]
b. 使用组合[]访问单个元素、赋值
// 声明一个 4*3 的多维数组
var mist_3 [4][3]int
var mist_4 [4][3]int
mist_3[0][0] = 10
mist_3[1][1] = 20
mist_3[2][2] = 30
mist_3[4] = [5, 7]
// mist_3 赋值给 mist_4
mist_4 = mist_3
var mist_5 [2]int = mist_4[1]
// 输出结果:
// == mist_3: [[10 0 0] [0 20 0] [0 0 30] [40 0 0]]
// == mist_4: [[10 0 0] [0 20 0] [0 0 30] [40 0 0]]
// == mist_5: [0 20 0]
5. 函数间传递数组
根据函数内存的内存和性能的消耗来说,函数间的传递数组使用指针比数组更有效的减少开销,函数间传递变量,是以值的形式传递的,每传递一次就会复制一次数据,当处理大数时,会额外增加内存和性能的开销
使用值传递大数
// 声明一个大数变量
var mist_6 [1e6]int
// 将大数传递给函数rain
rain(mist_6)
// rain 函数接受一个大数数组
func rain(mist_6 [1e6]int){
fmt.Println("==length rain: ", len(mist_6))
}
// 输出结果:
// ==length rain: 1000000
使用指针在函数间传递大数
由于传递的是指针,当修改指针的数值时会影响共享内存的数值
// 声明一个大数变量
var mist_6 [1e6]int
// 将大数指针传递给函数rain
rain(&mist_6)
// rain 函数接受一个大数数组指针
func rain(mist_6 *[1e6]int){
fmt.Println("==length rain: ", mist_6)
}
// 输出结果:
// ==length rain: 1000000