数组的声明和初始化
数组是所有语言编程中最常用的数据结构之一,Go语言也不例外,与PHP、JavaScript等弱类型动态语言不同,在Go语言中,数组是固定长度的、同一类型的数据集合。数组中包含的每个数据项被称为数组元素,一个数组包含的元素个数被称为数组的长度。
在Go语言中,你可以通过[]来标识数组类型,但需要指定长度和元素类型。以下是一些常见的数组声明方法:
vara[8]byte//长度为8的数组,每个元素为一个字节
varb[3][3]int//二维数组(9宫格)
varc[3][3][3]float64//三维数组(立体的9宫格)
vard=[3]int{1,2,3}//声明时初始化
vare=new([3]string)//通过new初始化
从以上示例可以看出,数组也可以是多维的。和普通变量赋值一样,数组也可以通过:=进行一次性声明和初始化,所有数组元素通过{}包裹,然后通过逗号分隔多个元素:
a:=[5]int{1,2,3,4,5}
总结一下,数组的格式定义如下所示:
[capacity]data_type{element_values}
此外,还可以通过这种语法糖省略数组长度的声明:
a:=[...]int{1,2,3}
这种情况下,Go会在编译期自动计算出数组长度。
数组在初始化的时候,如果没有填满,则空位会通过对应的元素类型零值填充:
a:=[5]int{1,2,3}
fmt.Println(a)
上述代码的打印结果是:
[]
此外,我们还可以初始化指定下标位置的元素值,未设置的位置也会以对应元素类型的零值填充:
a:=[5]int{1:3,3:7}
这样数组a的元素值如下:
[]
数组长度在声明后就不可更改,在声明时可以指定数组长度为一个常量或者一个常量表达式(常量表达式是指在编译期即可计算结果的表达式)。数组的长度是该数组类型的一个内置常量,可以用Go语言的内置函数len()来获取:
arrLength:=len(arr)
数组元素的访问和设置
可以使用数组下标来访问Go数组中的元素,数组下标默认从0开始,len(arr)-1表示最后一个元素的下标:
arr:=[5]int{1,2,3,4,5}
a1,a2:=arr[0],arr[len(arr)-1]
上面a1的值是1,a2的值是5。
访问数组元素时,下标必须在有效范围内,比如对于一个长度为5的数组,下标有效范围是0~4,超出这个范围编译时会报索引越界异常:
invalidarrayindex5(outofboundsfor5-elementarray)
和字符串这种不可变值类型不一样,数组除了支持通过下标访问对应索引的元素值之外,还可以通过下标设置对应索引位置的元素值:
arr[0]=
遍历数组
我们可以通过一个for循环遍历所有数组元素:
fori:=0;ilen(arr);i++{
fmt.Println("Element",i,"ofarris",arr[i])
}
上述代码的打印结果是:
Element0ofarris1
Element1ofarris2
Element2ofarris3
Element3ofarris4
Element4ofarris5
Go语言还提供了一个关键字range,用于以更优雅的方式遍历数组中的元素:
fori,v:=rangearr{
fmt.Println("Element",i,"ofarris",v)
}
range表达式返回两个值,第一个是数组下标索引值,第二个是索引对应数组元素值,如果我们不想获取索引值,可以这么做:
for_,v:=rangearr{
//...
}
如果只想获取索引值,可以这么做:
fori:=rangearr{
//...
}
多维数组
多维数组的操作与一维数组一样,只不过每个元素可能是个数组,在进行循环遍历的时候需要多层嵌套循环,下面我们通过Go语言的多维数组打印出九九乘法表来演示其基本使用:
//通过二维数组生成九九乘法表
varmulti[9][9]string
forj:=0;j9;j++{
fori:=0;i9;i++{
n1:=i+1
n2:=j+1
ifn1n2{//摒除重复的记录
continue
}
multi[i][j]=fmt.Sprintf("%dx%d=%d",n2,n1,n1*n2)
}
}
//打印九九乘法表
for_,v1:=rangemulti{
for_,v2:=rangev1{
fmt.Printf("%-8s",v2)//位宽为8,左对齐
}
fmt.Println()
}
执行上述代码,结果如下:
数组类型的不足
由于数组类型变量一旦声明后长度就固定了,这意味着我们将不能动态添加元素到数组,如果要这么做的话,需要先创建一个容量更大的数组,然后把老数组的元素都拷贝过来,最后再添加新的元素,如果数组尺寸很大的话,势必会影响程序性能。
另外,数组是值类型(关于值类型和引用类型,后面在Go类型系统中会详细介绍),这意味着作为参数传递到函数时,传递的是数组的值拷贝,也就是说,会先将数组拷贝给形参,然后在函数体中引用的是形参而不是原来的数组,当我们在函数中对数组元素进行修改时,并不会影响原来的数组,这种机制带来的另一个负面影响是当当数组很大时,值拷贝会降低程序性能。
综合以上因素,我们迫切需要一个引用类型的、支持动态添加元素的新「数组」类型,这就是下篇教程将要介绍的切片类型,实际上,我们在Go语言中很少使用数组,大多数时候会使用切片取代它。