3.1.2 数组
在Go语言中,数组的使用频率并不高,因为其长度不可变,所以很多时候都是使用slice(切片)。slice比数组更灵活,其长度是可变的。不过,在介绍slice之前,还是要先介绍一下数组,以增进读者对slice的理解,且数组也有一定的用武之地。
定义数组有如下几种方式:
var a [3]int var b [3]int = [3]int{1,2,3} c := [...]int{1,2,3} d := [...]int{4,4:1,1:2}
第一种方式就是定义一个长度为3的整型数组,里面的三个元素都是默认初始值0。
第二种方式是定义数组的同时进行初始化的赋值,这种定义方式有些冗余,精简操作就是把变量名称b后面的[3]int去掉,直接进行赋值。
第三种方式省略了数组长度,其长度由后面初始化值的长度确定。
第四种方式更为特殊,可以看到后面并没有给所有的元素赋值,而且赋值使用了index:value方式,比如4:1的意思就是给下标为4的元素赋值1。这时候数组长度根据出现的最大下标确定,上面的例子赋值完成后的值如下:
[4 2 0 0 1]
注意
在Go语言中,[3]int和[4]int是两种不同的数组类型,这两种不同的数组类型是在编译时就已经确定的。把[4]int赋值给[3]int的变量会报错,因为Go语言的数组长度是数组的一部分,并非像C语言那样只存储数组开始的地址。
在分配内存底层空间的时候,数组的元素是紧挨着分配到固定位置的,这也是数组长度不可变的原因。
接下来看几个例子:
book/ch03/3.1/array/main.go
1. package main
2.
3. import "fmt"
4.
5. func main() {
6. a := [...]int{1,2,3,4}
7. b := &a
8. fmt.Println(a[0],a[1])
9. fmt.Println(b[0],b[1])
10. var s = [...]string{"hello","世界"}
11. for i,v := range s {
12. fmt.Printf("s[%d]:%s\n",i,v)
13. }
14. for i:=0;i<len(s);i++{
15. fmt.Printf("s[%d]:%s\n",i,s[i])
16. }
17. }
18.
19. //以下是上面代码的执行结果
20. 1 2
21. 1 2
22. s[0]:hello
23. s[1]:世界
24. s[0]:hello
25. s[1]:世界
第7行,定义了一个指向数组a的指针b,按理来说通过b也可以访问数组a内的元素。结合第8行、第9行及对应的第20行、第21行的打印结果,可以验证通过指针b确实可以访问数组a的元素,其实也可以对指针b使用range方式遍历。
第10行,定义了一个字符串数组,而且字符里面有汉字。
第11行至第17行,对字符串s使用两种方式进行了遍历。看第22行至第25行的打印结果可知,两种方式得到的结果是一样的。不过还是建议读者使用range,因为这种方式不会出现数组下标越界的问题。
数组的元素可以是基本数据类型,也可以是接口、结构体等,这些数据结构马上就会介绍。
我们也可以定义0个元素的数组:
var d [0]int
注意
在使用数组时一定要注意,Go语言的数组是传递值的,而通常其他语言的数组都是传递引用的。如果读者要使用数组作为一个函数的参数,请使用指针方式,要不然函数形参接收到的数组其实是完全复制了一份,不仅浪费性能,而且对于形参数组的修改不会影响到原数组。