这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
数组
Go语言中的数组是具有相同类型, 有编号的, 长度固定的一组数据.
数组中的元素可以是布尔, 整型, 字符串, 也可以是自定义类型
数组的长度是一个非负正整数的常量
数组的下标从零开始
Go中的数组是一个值类型, 而不是一个对象类型或者引用类型
数组的类型包括数组的长度. 如果存储的类型一样, 但是长度不一样,那么它们也不是同一种类型
数组的定义
定义数组不赋值
数组在被定义时, 会将数组中各元素的值, 初始化为它们的零值
大家可以查看前面的文章: Go中的数据类型
// 定义整型数组
// 输出: [3]int{0, 0, 0}
var list [3]int
fmt.Printf("%#v\n", list)
// 定义字符串数组
// 输出: [3]string{"", "", ""}
var names [3]string
fmt.Printf("%#v\n", names)
定义不同类型的数组
// 定义一个整型数组
ages := [5]int {11, 22, 33, 44, 55}
fmt.Println(ages)
// 定义一个浮点型数组
prices := [3]float64 {1.3, 3.5, 5.7}
fmt.Println(prices)
// 定义一个字符串数组
bookNames := [3]string {"ThreeBody1", "ThreeBody2", "ThreeBody3"}
fmt.Println(bookNames)
不指定数组长度的定义
// 不指明数组数量, 由后面数组数量自动推断
// 输出: 数组: [3]int{1, 3, 5}
arr := [...]int {1, 3, 5}
fmt.Printf("数组: %#v\n", arr)
指定位置元素的值
// 指定位置元素的值
// 输出: 数组: [4]int{8, 6, 4, 2}
arr2 := [...]int {0:8, 1:6, 2:4, 3:2}
fmt.Printf("数组: %#v\n", arr2)
// 按顺序初始化数组中的几个元素, 再指定特定位置的元素的值
/*
如果没有明确元素个数, 由指定位置决定数组长度
输出: [12]int{1, 3, 5, 0, 0, 0, 0, 2, 0, 4, 0, 6}
*/
arr3 := [...]int {1, 3, 5, 7:2, 9:4, 11:6}
fmt.Printf("数组: %#v\n", arr3)
使用new来创建一个数组
// 使用new来创建一个数组
// 输出: &[3]int{0, 0, 0}
newArr := new([3]int)
fmt.Printf("%#v\n", newArr)
使用new来创建一个数组, 和上面其它的方式, 又有什么区别呢? &[3]int{0, 0, 0} [3]int{0, 0, 0} 这两种类型它不是同一种类型, 一个是&[3]int, 一个是[3]int 使用new创建出来的数组, 在打印它的类型的时候, 多了&表明它返回的是一个地址,
而不使用new来创建的数组, 返回的是数组这个值
list1 := new([3]int)
list2 := list1
list2[1] = 10
fmt.Println(list1)
fmt.Println(list2) // 输出结果一样, 证明list1和list2操作的是同一个数组
var list3 [3]int
list4 := list3
list4[2] = 200
fmt.Println(list3)
fmt.Println(list4) // 输出结果不一样, 证明list3和list4是不同的数组
数组作为函数参数
// 数组作为函数参数
/*
当数组作为函数参数的时候, 会进行值传递, 所以会浪费大量内存, 一般不建义这样使用
*/
intArr := [3]int {1, 3, 5}
fmt.Printf("main函数内调用changeArr函数之前: %#v\n",arr)
changeArr(intArr)
fmt.Printf("main函数内调用changeArr函数之后: %#v\n",arr)
func changeArr(arr [3]int) {
arr[1] = 100
// 函数内
fmt.Printf("changeArr函数内更改数组值之后: %#v\n",arr)
}
数组指针作为函数参数
// 使用数组指针作为函数参数
intArr2 := new([3]int)
intArr2[0] = 2
intArr2[1] = 4
intArr2[2] = 6
fmt.Printf("main函数内调用changeArr2函数之前: %#v\n",intArr2)
changeArr2(intArr2)
fmt.Printf("main函数内调用changeArr2函数之后: %#v\n",intArr2)
func changeArr2(arr *[3]int) {
arr[1] = 100
// 函数内
fmt.Printf("changeArr2函数内更改数组值之后: %#v\n",arr)
}
Go语言中的多维数组
// 二组数组, 类型: [2][3]int
twoGroupArr := [2][3]int {{1, 3, 5}, {2, 4, 6}}
fmt.Println(twoGroupArr)
// 二组数组的长度
// 多维数组的长度只返回第一维的长度
fmt.Println(len(twoGroupArr))
// 三维数组, 类型 : [3][2][4]int
threeGroupArr := [3][2][4]int {
{
{1, 2, 3, 4},
{},
},
{
{},
{5, 6, 7, 8},
},
}
fmt.Println(threeGroupArr)
// 三组数组的长度
// 多维数组的长度只返回第一维的长度
fmt.Println(len(threeGroupArr))
...在多维数组中的使用
// ...只能在第一维使用
twoGroupArr2 := [...][3]int {{1, 2, 3}, {3, 4, 5}}
fmt.Printf("%#v\n", twoGroupArr2)
数组的访问
一组数组的访问
// 一组数组的访问
oneArr := [...]int {1, 3, 5, 7, 9}
// 通过下标访问, 从0开始, 最大下标: 数组长度-1
oneArr[1] = 10
oneArr[4] = 100
// 使用for循环访问一维数组
for i := 0; i < len(oneArr); i++ {
fmt.Println(oneArr[i])
}
// 使用for...range访问一维数组
for i, v := range oneArr {
fmt.Println(i, v)
}
多维数组的访问
// 多维数组的访问
twoArr := [2][3]int {{1, 3, 5}, {2, 4, 6}}
// 通过下标访问
fmt.Println("第1行的第2个元素: ",twoArr[0][1])
fmt.Println("第2行的第3个元素: ", twoArr[1][2])
// for循环访问多维数组
for i := 0; i < len(twoArr); i++ {
for j := 0; j < len(twoArr[0]); j++ {
fmt.Printf("%v ", twoArr[i][j])
}
fmt.Println()
}
// for...range访问多维数组
for _, v := range twoArr {
for _, v2 := range v {
fmt.Printf("%v ", v2)
}
fmt.Println()
}
总结
Go中的数组, 好像跟其它的数组有那么点不一样, 用起来不是很灵活, 类型固定, 数组的类型包括它的长度. 当作为参数的时候, 它是值传递, 也就是在函数调用的时候, 还是会开辟一块同样大小的空间, 将数组的值拷贝过去, 造成浪费. 如果只是在代码块内部使用, 并且已经确定数组的长度, 那就可以使用, 否则请使用切片!!!