数组
数组的定义
数组是一种存储相同数据类型的元素的定长容器,在 Go 语言中有一维数组和多维数组。
先介绍一维数组的语法格式和示例。
语法格式:
var 数组名 [长度]数据类型
// 使用var关键字定义
var 数组名 [长度]数据类型 = [长度]数据类型{元素1, 元素2, 元素3, ..., 元素n}
// 使用类型推断的方式
var 数组名 = [长度]数据类型{元素1, 元素2, 元素3, ..., 元素n}
// 使用简短定义的方式
数组名 := [长度]数据类型{元素1, 元素2, 元素3, ..., 元素n}
var 数组名 [长度]数据类型
数组名 = [长度]数据类型{元素1, 元素2, 元素3, ..., 元素n}
示例:
package main
import "fmt"
func main() {
// 定义数组语法:var 数组名 [长度]数据类型
var arr1 [5]int
fmt.Printf("arr1 = %v\n", arr1) // [0 0 0 0 0]
// 定义数组并初始化
arr2 := [5]bool{true, false, true, false, true}
fmt.Printf("arr2 = %v\n", arr2)
// 定义数组并初始化
var arr3 [5]string
arr3 = [5]string{"a", "b", "c", "d", "e"}
fmt.Printf("arr3 = %v\n", arr3)
}
访问数组元素
数组的每一个元素都可以通过下标索引的方式来访问。
语法格式:
// 索引不存在,编译不通过
数组名[索引]
示例:
package main
import "fmt"
func main() {
// 创建一个int类型长度为6的数组
var arr1 [5]int = [5]int{13, 25, 33, 46, 55}
// 通过数组索引访问数组元素
fmt.Println(arr1[0]) // 13
fmt.Println(arr1[1]) // 25
fmt.Println(arr1[2]) // 33
fmt.Println(arr1[3]) // 46
fmt.Println(arr1[4]) // 55
// 访问不存在的索引
// fmt.Println(arr1[5]) // 编译不通过
}
获取数组长度
索引的范围从0开始到数组的长度减1的位置结束,可以通过 len()
函数来获取数组的长度【数组中的元素个数】。
语法格式:
// v可以是以下几种类型: array、slice、string、map、channel
len(v)
示例:
package main
import "fmt"
func main() {
// 使用len()函数获取数组长度
var arr = [10]int{13, 23, 36, 44, 58, 64, 72, 88, 91}
fmt.Printf("数组长度为:%d\n", len(arr)) // 数组长度为:10
}
数组的初始化元素默认值
在初始化数组时每一个元素的初始化都是数据类型的初始值,数值型: 0、字符串: ""、布尔类型: false、浮点类型: 0.0等。
示例:
package main
import "fmt"
func main() {
// int类型的数组
var a1 [3]int
fmt.Printf("a1 = %v\n", a1) // a1 = [0 0 0]
// bool类型的数组
var a2 [3]bool
fmt.Printf("a2 = %v\n", a2) // a2 = [false false false]
// string类型的数组
var a3 [3]string
fmt.Printf("a3 = %v\n", a3) // a3 = [ ]
// float64类型的数组
var a4 [3]float64
fmt.Printf("a4 = %v\n", a4) // a4 = [0 0 0]
}
使用...替代数组长度
在定义数组并初始化数组元素时,可以使用 ...
来替代数组的长度,...
表示数组的长度根据数组的元素个数来推断数组的长度。
示例:
package main
import "fmt"
func main() {
// 在定义数组并初始化数组元素时可以使用...来替代数组的长度
var a = [...]int{1, 2, 3, 4, 5} // 定义数组并初始化数组元素
fmt.Printf("a = %v\n", a) // a = [1 2 3 4 5]
}
比较数组内元素是否相同
如果两个数组类型相同(长度相同、数据类型相同)的情况下,可以使用 ==
或者 !=
的方式来判断两个数组是否相同,只有当两个数组的所有元素都是相等的时候数组才是相等的,不能比较两个类型不同的数组,否则程序将无法完成编译。
示例:
package main
import "fmt"
func main() {
// 使用==判断两个数组是否相同
a1 := [...]int{1, 2, 3}
a2 := [...]int{1, 2, 3}
fmt.Printf("a1类型:%T\n", a1)
fmt.Printf("a2类型:%T\n", a2)
fmt.Printf("a1 == a2 结果:%t\n", (a1 == a2))
// 使用==判断两个数组是否相同
a3 := [...]int{11, 2, 3}
fmt.Printf("a3类型:%T\n", a3)
fmt.Printf("a1 == a3 结果:%t\n", (a1 == a3))
// 使用!=判断两个数组是否不相同
fmt.Printf("a1 != a2 结果:%t\n", (a1 != a2))
fmt.Printf("a1 != a3 结果:%t\n", (a1 != a3))
// 注意事项:必须是两个数组类型相同才能进行比较。【数据类型相同:长度相同、数据类型相同】
// a4 := [...]int{1, 2, 3, 4}
// fmt.Printf("a1 == a4 结果:%t\n", (a1 == a4)) // 编译不通过
}
遍历数组
可以使用 for
语句或者 for range
语句来对数组进行遍历操作。
示例:
package main
import "fmt"
func main() {
// 定义一个字符串数组长度为5
s1 := [5]string{"Go", "Java", "C++", "Python", "Rust"}
// 使用for循环遍历数组
for i := 0; i < len(s1); i++ {
println(s1[i])
}
fmt.Println("========================")
// 使用for range遍历数组
for index, value := range s1 {
println(index, value)
}
}
数组是值类型
在Go语言中数组是值类型,而不是引用类型,也就是当一个数组被赋值给另一个变量时,实际上是创建了一个新的数组,并将原来数组的值拷贝到了这个新数组中【值拷贝】,如果对新数组进行修改,原数组不会受影响。
示例:
package main
import "fmt"
func main() {
// 数组是值类型
arr1 := [3]int{1, 2, 3}
arr2 := arr1
var arr3 [3]int
arr3 = arr1
// 打印arr1、arr2、arr3的内存地址和值
fmt.Printf("arr1地址:%p,arr1值:%#v\n", &arr1, arr1)
fmt.Printf("arr2地址:%p,arr2值:%#v\n", &arr2, arr2)
fmt.Printf("arr3地址:%p,arr3值:%#v\n", &arr3, arr3)
fmt.Println("=======================================")
// 对arr2数组的第二个元素进行修改
arr2[1] = 200
// 对arr3数组的第三个元素进行修改
arr3[2] = 300
// 再打印arr1、arr2、arr3的内存地址和值
fmt.Printf("arr1地址:%p,arr1值:%#v\n", &arr1, arr1)
fmt.Printf("arr2地址:%p,arr2值:%#v\n", &arr2, arr2)
fmt.Printf("arr3地址:%p,arr3值:%#v\n", &arr3, arr3)
}
长度也是数组类型组成部分
数组的长度也是数组类型的组成部分,因此 [5]int
和 [6]int
是两种不同的数组类型。
示例:
package main
import "fmt"
func main() {
// [5]int和[6]int是两种不同的数组类型
a1 := [5]int{1, 2, 3, 4, 5}
fmt.Printf("a1的值:%v\n", a1)
// a1 = [6]int{1, 2, 3, 4, 5, 6} // 编译不通过
a1 = [5]int{11, 22, 33, 44, 55}
fmt.Printf("a1的值:%v\n", a1)
}
多维数组
在 Go 语言中,多维数组是由数组的数组组成的。最常见的多维数组是二维数组,但是你可以创建任意数量的维度。
多维数组主要用于场景,其中需要存储和操作表格数据或其他形式的网格,例如在矩阵运算或图形计算中。然而,当你需要一个动态大小的多维结构时,应该使用切片的切片。
语法格式:
var 变量名 [长度1][长度2]...[长度n] 数据类型
示例:
package main
import "fmt"
func main() {
// 定义一个[4][3]的二维数组。(多维数组同理)
// 有4个一维数组,每个一维数组的长度都是3
var array [4][3]int
array = [4][3]int{
{1, 2, 3}, // [0,0] [0,1] [0,2]
{4, 5, 6}, // [1,0] [1,1] [1,2]
{7, 8, 9}, // [2,0] [2,1] [2,2]
{10, 11, 12}, // [3,0] [3,1] [3,2]
}
for i := 0; i < len(array); i++ {
for j := 0; j < len(array[i]); j++ {
fmt.Printf("arr[%d][%d]:%v\n", i, j, array[i][j])
}
}
}
package main
import "fmt"
func main() {
// 定义一个三维数组
var array3D [2][3][4]int
// 给数组赋值
// 2 表示这个三维数组有 2 个二维数组。
// 3 表示每个二维数组有 3 个一维数组(行)。
// 4 表示每个一维数组有 4 个元素(列)。
// 个数计算:2 * 3 * 4 = 24
array3D = [2][3][4]int{
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
},
{
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24},
},
}
fmt.Println(array3D)
}
使用数组注意事项
数组使用时的注意事项
- 固定大小:Go中的数组是固定大小的。数组的长度是其类型的一部分,一旦声明,数组的大小就不能改变。
- 值类型:Go中的数组是值类型,这意味着当它们被赋值给一个新变量或者作为参数传递给函数时,实际上会复制整个数组。如果数组比较大,这可能会导致性能问题。
- 初始化:你可以在声明数组时初始化数组元素。如果不初始化,默认情况下,数值数组元素将被初始化为0,字符串数组为空字符串,布尔数组元素为false。
- 索引:数组的索引从0开始,尝试访问超出数组长度范围的索引会产生运行时错误(out of range)。
- 多维数组:在 Go 中,可以创建多维数组。在使用时,你要为每个维度提供大小,并记住它们的索引也是从0开始的。
- 迭代:可以使用for循环或for...range结构来迭代数组。
- 内存布局:数组中的元素在内存中是连续存放的。
请记住,在需要动态大小集合的时候,应该使用切片(slice),而不是数组,因为切片比数组更加灵活。