数组 (array) 就是由若干个相同类型的元素组成的序列.
var ipv4 [4]uint8 = [4]uint8(192,168,0,1)
在这条赋值语句中, 我们为刚声明的变量 ipv4 赋值. 在这种情况下, 变量名右边的类型字面量可以省略.
如果它在函数里面, 那么关键字 var 也可以省略, 但赋值符号必须由 = 变为:=.
类型字面量[4]uint8 表明这个变量的类型长度为 4 且元素类型为 uint 的数组类型.
注意, 数组的长度是数组类型的一部分.
只要类型声明中的数组长度不同, 即两个数组类型的元素类型相同, 它们也是不同的类型.
更重要的是, 一旦在声明中确定了数组类型的长度, 就无法改变它了.
同时, 同一类型的数组可以使用操作符 ==,!=.
- 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
- }
数组初始化的方式比较灵活.
数组类型的零值一定是一个不包含任何元素的空数组.
一个类型的零值即为该类型变量未被显式赋值时的默认值.
- 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]
- }
对于结构等复杂类型, 可省略元素初始化类型标签.
- 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 都只能返回第一维度的长度.
- 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
- */
要注意区分指针数组和数组指针.
指针数组: 元素为指针类型的数组; 数组指针: 获取数组变量的指针.
- 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]
- }
通过指针可以反取数据.
- package main
- import "fmt"
- func main() {
- a := [2]int{1, 2}
- p := &a
- fmt.Println(*p) //[1 2]
- }
Go 数组是值类型, 复制和传参都会复制整个数组.
数组的指针是数组中第一个元素的指针.
数组是内层中某个连续的片段, 复制和赋值都会在此分配片段, 这属于值复制, 指针也不同.
- 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
- }
如果需要, 可改用指针或切片, 这样就可以避免复制, 以此可以减少资源的消耗.
- 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]
- */
当需要详细规划程序所用的内存时, 数组类型非常有用.
使用数组值可以完全避免耗时费力的内存二次分配操作, 因为它的长度是不可改变的.
来源: http://www.bubuko.com/infodetail-2877786.html