数组
数组是Go语言编程中最常用的数据结构之一。顾名思义,数组就是指一系列同一类型数据的集合。数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数组的长度。
注意事项:如果我们想让数组元素类型为任意类型的话可以使用空接口作为类型。当使用值时我们必须先做一个类型判断。
以下为一些常规的数组声明方法:
[32]byte // 长度为32的数组,每个元素为一个字节 [2*N] struct { x, y int32 } // 复杂类型数组 [1000]*float64 // 指针数组 [3][5]int // 二维数组 [2][2][2]float64 // 等同于[2]([2]([2]float64))
var arr1 [5]int在go语言的内存结构
在Go语言中,数组长度在定义后就不可更改,在声明时长度可以为一个常量或者一个常量表达式(常量表达式是指在编译期即可计算结果的表达式)。数组的长度是该数组类型的一个内置常量,可以用Go语言的内置函数len()来获取。下面是一个获取数组arr元素个数的写法:
arrLength := len(arr)
元素访问
可以使用数组下标来访问数组中的元素。与大多数语言相同,数组下标从0开始,len(array)-1则表示最后一个元素的下标。下面的示例遍历整型数组并逐个打印元素内容:
for i := 0; i < len(array); i++ { fmt.Println("Element", i, "of array is", array[i]) }
Go语言还提供了一个关键字range,用于便捷地遍历容器中的元素。上面的遍历过程可以简化为如下的写法:
for i, v := range array { fmt.Println("Array element[", i, "]=", v) }
在上面的例子里可以看到,range具有两个返回值,第一个返回值是元素的数组下标,第二个返回值是元素的值。
值类型
需要特别注意的是,在Go语言中数组是一个值类型(value type)。所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。如果将数组作为函数的参数类型,则在函数调用时该参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所传入数组的一个副本。
下面用例子来说明这一特点:
package main import "fmt" func modify(array [10]int) { array[0] = 10 // 试图修改数组的第一个元素 fmt.Println("In modify(), array values:", array) } func main() { array := [5]int{1,2,3,4,5} // 定义并初始化一个数组 modify(array) // 传递给一个函数,并试图在函数体内修改这个数组内容 fmt.Println("In main(), array values:", array) }
该程序的执行结果为:
In modify(), array values: [10 2 3 4 5]
如果你想修改原数组,那么 arr2 必须通过&操作符以引用方式传过来,例如 func1(&arr2)
package main import "fmt" func f(a [3]int) { fmt.Println(a) } func fp(a *[3]int) { fmt.Println(a) } func main() { var ar [3]int f(ar) // passes a copy of ar fp(&ar) // passes a pointer to ar }
数组切片
数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。Go语言提供了数组切片(slice)这个非常酷的功能来弥补数组的不足。数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构,而不仅仅是个指针。数组切片的数据结构可以抽象为以下3个变量:
一个指向原生数组的指针;
数组切片中的元素个数;
数组切片已分配的存储空间。
从底层实现的角度来看,数组切片实际上仍然使用数组来管理元素.基于数组,数组切片添加了一系列管理功能,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制。
创建数组切片
创建数组切片的方法主要有两种——基于数组和直接创建,下面我们来简要介绍一下这两种方法。
基于数组
数组切片可以基于一个已存在的数组创建。数组切片可以只使用数组的一部分元素或者整个数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片。代码清单2-1演示了如何基
于一个数组的前5个元素创建一个数组切片。
package main import "fmt" func main() { // 先定义一个数组 var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} // 基于数组创建一个数组切片 var mySlice []int = myArray[:5] fmt.Println("Elements of myArray: ") for _, v := range myArray { fmt.Print(v, " ") } fmt.Println("\nElements of mySlice: ") for _, v := range mySlice { fmt.Print(v, " ") } fmt.Println() }
运行结果为:
Elements of myArray:
1 2 3 4 5 6 7 8 9 10
Elements of mySlice:
1 2 3 4 5
读者应该已经注意到,Go语言支持用myArray[first:last]这样的方式来基于数组生成一
个数组切片,而且这个用法还很灵活,比如下面几种都是合法的。
基于myArray的所有元素创建数组切片:
mySlice = myArray[:]
基于myArray的前5个元素创建数组切片:
mySlice = myArray[:5]
基于从第5个元素开始的所有元素创建数组切片:
mySlice = myArray[5:]
直接创建
Go语言提供的内置函数**make()**可以用于灵活地创建数组切片。下面的例子示范了直接创建数组切片的各种方法。
:
//创建一个初始元素个数为5的数组切片,元素初始值为0: mySlice1 := make([]int, 5) //创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间: mySlice2 := make([]int, 5, 10) //直接创建并初始化包含5个元素的数组切片: mySlice3 := []int{1, 2, 3, 4, 5}
元素遍历
操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len()函数获取元素个数,并支持使用range关键字来快速遍历所有元素。
for i := 0; i <len(mySlice); i++ { fmt.Println("mySlice[", i, "] =", mySlice[i]) } //使用range关键字可以让遍历代码显得更整洁。range表达式有两个返回值,第一个是索引,第二个是元素的值: for i, v := range mySlice { fmt.Println("mySlice[", i, "] =", v) }
go语言中的数组与切片(二)https://developer.aliyun.com/article/1391424