go——数组
数组(array)就是由若干个相同类型的元素组成的序列。
1 | var ipv4 [4]uint8 = [4]uint8(192,168,0,1) |
在这条赋值语句中,我们为刚声明的变量ipv4赋值。在这种情况下,变量名右边的类型字面量可以省略。
如果它在函数里面,那么关键字var也可以省略,但赋值符号必须由=变为:=。
类型字面量[4]uint8表明这个变量的类型长度为4且元素类型为uint的数组类型。
注意,数组的长度是数组类型的一部分。
只要类型声明中的数组长度不同,即两个数组类型的元素类型相同,它们也是不同的类型。
更重要的是,一旦在声明中确定了数组类型的长度,就无法改变它了。
同时,同一类型的数组可以使用操作符==、!=。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package main import "fmt" var d0 [2]int //d0是数组类型的变量,因此也要遵循变量使用原则,全局变量可以只定义不使用,但是局部变量不行。 func main() { var d1 [3]int var d2 [2]int fmt.Println(d1 == d2) //invalid operation: d1 == d2 (mismatched types [3]int and [2]int)长度不同 d3 := [2]int{1, 2} d4 := [2]int{2, 3} fmt.Println(d3 != d4) //true } |
数组初始化的方式比较灵活。
数组类型的零值一定是一个不包含任何元素的空数组。
一个类型的零值即为该类型变量未被显式赋值时的默认值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package main import "fmt" func main() { var a [3]int b := [4]int{2, 3} c := [4]int{5, 3: 10} d := [...]int{1, 2, 3} e := [...]int{3, 4, 4: 9} fmt.Println(a) //[0 0 0] int类型的元素默认值为0 fmt.Println(b) //[2 3 0 0] 位提供初始化的元素自动使用默认值 fmt.Println(c) //[5 0 0 10] 3:10表示元素10是数组的第4个元素 fmt.Println(d) //[1 2 3] 省略长度,但不是没有,编译器按照初始化元素的数量确定长度 fmt.Println(e) //[3 4 0 0 9] } |
对于结构等复杂类型,可省略元素初始化类型标签。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package main import "fmt" func main() { type user struct { name string age int } d := [...]user{ { "kebi" , 26}, //省略类型标签 { "maoxian" , 24}, } fmt.Println(d) //[{kebi 26} {maoxian 24}] } |
在定义多维数组时,仅第一维数组可以使用"..."。
内置函数len和cap都只能返回第一维度的长度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package main import "fmt" func main() { a := [2][3]int{ {1, 2, 3}, {4, 5}, } b := [...][2]int{ {4, 2}, {3, 4}, } fmt.Println(a, len(a), cap(a)) fmt.Println(b, len(b), cap(b)) } /* [[1 2 3] [4 5 0]] 2 2 [[4 2] [3 4]] 2 2 */ |
要注意区分指针数组和数组指针。
指针数组:元素为指针类型的数组;数组指针:获取数组变量的指针。
1 2 3 4 5 6 7 8 9 10 11 12 13 | package main import "fmt" func main() { a := [...]int{1, 2, 3} fmt.Println(&a) //数组没有指针,只有数组的元素才有指针,数组只是对底层元素的包装 fmt.Println(&a[0], &a[1]) //数组指针 0xc00004c0c0 0xc00004c0c8 x, y := 10, 20 b := [2]*int{&x, &y} //指针数组 fmt.Println(b) [0xc00004c0c0 0xc00004c0c8] } |
通过指针可以反取数据。
1 2 3 4 5 6 7 8 9 | package main import "fmt" func main() { a := [2]int{1, 2} p := &a fmt.Println(*p) //[1 2] } |
Go数组是值类型,复制和传参都会复制整个数组。
数组的指针是数组中第一个元素的指针。
数组是内层中某个连续的片段,复制和赋值都会在此分配片段,这属于值复制,指针也不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package main import "fmt" func test(x [2]int) { fmt.Printf( "x: %p, %v\n" , &x, x) } func main() { a := [2]int{10, 20} var b [2]int b = a //复制 fmt.Printf( "a: %p, %v\n" , &a, a) //a: 0xc00004e080, [10 20] fmt.Printf( "b: %p, %v\n" , &b, b) //b: 0xc00004e090, [10 20] test(a) //传参//x: 0xc00004e0f0, [10 20] fmt.Println(&a[0], &a[1]) //0xc00004e080 0xc00004e088 fmt.Println(&b[0], &b[1]) //0xc00004e090 0xc00004e098 } |
如果需要,可改用指针或切片,这样就可以避免复制,以此可以减少资源的消耗。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package main import "fmt" func test(x *[2]int) { fmt.Printf( "x: %p, %v\n" , x, *x) } func main() { a := [2]int{10, 20} test(&a) //直接传递的是指针,这样就避免复制 fmt.Printf( "a: %p, %v\n" , &a, a) } /* x: 0xc00004e080, [10 20] a: 0xc00004e080, [10 20] */ |
当需要详细规划程序所用的内存时,数组类型非常有用。
使用数组值可以完全避免耗时费力的内存二次分配操作,因为它的长度是不可改变的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理