Go从入门到放弃4--数组

160 阅读3分钟

数组是由相同类型元素的集合组成的数据结构,计算机会为数组分配一块连续的内存来保存其中的元素,我们可以利用数组中元素的索引快速访问特定元素,内置的len函数将返回数组中元素的个数。

var a [3]int             // array of 3 integers
fmt.Println(a[0])        // print the first element
fmt.Println(a[len(a)-1]) // print the last element, a[2]

数组作为一种基本的数据类型,我们通常会从两个维度描述数组,也就是数组中存储的元素类型和数组最大能存储的元素个数,Go 语言数组在初始化之后大小就无法改变,存储元素类型相同、但是大小不同的数组类型在 Go 语言看来也是完全不同的,只有两个条件都相同才是同一类型。

func foo(arr [5]int) {}
func main() {
    var arr1 [5]int
    var arr2 [6]int
    var arr3 [5]string

    foo(arr1) // ok
    foo(arr2) // 错误:[6]int与函数foo参数的类型[5]int不是同一数组类型
    foo(arr3) // 错误:[5]string与函数foo参数的类型[5]int不是同一数组类型
}  

数组初始化

Go 语言的数组有两种不同的创建方式,一种是显式的指定数组大小,另一种是使用 [...]T 声明数组,Go 语言会在编译期间通过源代码推导数组的大小:

arr1 := [3]int{1, 2, 3}
arr2 := [...]int{1, 2, 3}

和基本数据类型一样,我们声明一个数组类型变量的同时,也可以显式地对它进行初始化。如果不进行显式初始化,那么数组中的元素值就是它类型的零值。

var arr1 [6]int // [0 0 0 0 0 0]

访问和赋值

数组在内存中都是一连串的内存空间,我们通过指向数组开头的指针、元素的数量以及元素类型占的空间大小表示数组。如果我们不知道数组中元素的数量,访问时可能发生越界;而如果不知道数组中元素类型的大小,就没有办法知道应该一次取出多少字节的数据,无论丢失了哪个信息,我们都无法知道这片连续的内存空间到底存储了什么数据.

数组访问越界是非常严重的错误,Go 语言中可以在编译期间的静态类型检查判断数组越界。

数组的问题

数组类型变量是一个整体,这就意味着一个数组变量表示的是整个数组。当调用一个函数的时候,函数的每个调用参数将会被赋值给函数内部的参数变量,所以函数参数变量接收的是一个复制的副本,并不是原始调用的变量。Go 传递数组的方式都是纯粹的值拷贝,这会带来较大的内存拷贝开销,并且对数组参数的任何的修改都是发生在复制的数组上,并不能直接修改调用时原始的数组变量。

参考资料

  • 《Go语言圣经》
  • 《Go语言第一课》
  • 《 Go语言设计与实现》