From 05488689f037b4bd2ee5f9046b72b2076c589737 Mon Sep 17 00:00:00 2001 From: WilberTian Date: Thu, 28 Dec 2017 22:23:28 +0800 Subject: [PATCH] udpate note about go array --- .../Go\346\225\260\347\273\204.md" | 132 ++++++++++++------ 1 file changed, 92 insertions(+), 40 deletions(-) mode change 100644 => 100755 "02.Go\346\225\260\347\273\204/Go\346\225\260\347\273\204.md" diff --git "a/02.Go\346\225\260\347\273\204/Go\346\225\260\347\273\204.md" "b/02.Go\346\225\260\347\273\204/Go\346\225\260\347\273\204.md" old mode 100644 new mode 100755 index c960c3d..08d4ddb --- "a/02.Go\346\225\260\347\273\204/Go\346\225\260\347\273\204.md" +++ "b/02.Go\346\225\260\347\273\204/Go\346\225\260\347\273\204.md" @@ -1,70 +1,122 @@ +Go和其他语言一样,也有数组类型,数组是长度固定的数据类型,必须存储一段相同类型的元素。数组存储的类型可以是内置类型,比如整型或者字符串,也可以是自定义的数据结构。 + + + +### Go语言的数组 +但是Go语言的数组又有特殊的地方: + +- 数组是值类型,赋值和传参会复制整个数组,⽽不是指针(在Go语言中,所有的赋值都是传值) +- 数组⻓度必须是常量,并且数组长度是数组类型的组成部分,也就是说`[2]int`和`[3]int`是不同类型 +- 数组⽀持 "=="、"!=" 操作符 +- 指针数组 [n]*T,数组指针 *[n]T + + + ### 声明和初始化 -var nums [6]int +数组的声明需要表明: +- 存储数据的类型 +- 存储元素的数量,即数组长度 -var nums [6]int -nums = [6]int{1, 2, 3, 4, 5, 6} +例如,下面代码声明了一个数组`array`,但是还没有对它进行初始化,这时候数组里面的值是对应元素类型的零值。 + + var nums [6]int -nums := [6]int{1, 2, 3, 4, 5, 6} +数组一旦声明后,其元素类型和大小都不能变了,如果还需要存储更多的元素,那么只能通过创建一个新的数组,然后把原来数组的数据复制过去。 +刚刚声明的数组已经被默认的元素类型零值初始化了,如果再次进行初始化,可以采用如下办法: -nums := [...]int{1, 2, 3, 4, 5, 6} + var nums [6]int + nums = [6]int{1, 2, 3, 4, 5, 6} +Go为我们提供了`:=`操作符(不仅适用于数组,还适用于任何数据类型,**但是只能用在函数中**),可以在创建数组的时候直接初始化: -array := [6]int{0, 1, 0, 4, 0, 0} -array := [6]int{1: 1, 3: 4} + nums := [6]int{1, 2, 3, 4, 5, 6} + +当然也可以连数组的长度都不指定,使用`...`代替,Go会自动推导出数组的长度: + + nums := [...]int{1, 2, 3, 4, 5, 6} + +假如只想给索引为1和3的数组初始化相应的值,其他都为0,直接的办法如下: + + array := [6]int{0, 1, 0, 4, 0, 0} + +还有一种简便的办法,前面讲到数组默认初始化为零值,那么就可以利用这个特性,只初始化索引1和3的值: + + array := [6]int{1: 1, 3: 4} ### 数组遍历 -func main() { - array := [5]int{1: 1, 3: 4} - for i := 0; i < 5; i++ { - fmt.Printf("索引:%d,值:%d\n", i, array[i]) +数组元素的访问直接通过操作符`[]`即可,同样数组的遍历也非常方便。 + +可以直接使用`len`得到数组的长度,然后通过`for`进行遍历: + + func main() { + array := [5]int{1: 1, 3: 4} + + for i := 0; i < len(array); i++ { + fmt.Printf("索引:%d,值:%d\n", i, array[i]) + } } -} +在Go中,也可以直接使用`for range`对数组进行遍历: -func main() { - array := [5]int{1: 1, 3: 4} - for i, v := range array { - fmt.Printf("索引:%d,值:%d\n", i, v) + func main() { + array := [5]int{1: 1, 3: 4} + + for i, v := range array { + fmt.Printf("索引:%d,值:%d\n", i, v) + } } -} -### 数组作为函数参数 -同样类型的数组是可以相互赋值的,不同类型的不行,会编译错误。那么什么是同样类型的数组呢?Go语言规定,必须是长度一样,并且每个元素的类型也一样的数组,才是同样类型的数组。 +### 数组的赋值 + +前面提到,数组是值类型,赋值和传参会复制整个数组。下面就通过一个例子验证: -array := [5]int{1: 1, 3: 4} -var array1 [5]int = array //success -var array2 [4]int = array1 //error + func main() { + arr1 := [3]int{1, 2, 3} + arr2 := arr1 + arr2[2] = 10 + + fmt.Println(arr1) + fmt.Println(arr2) + } +代码的输出为: -func main() { - array := [5]int{1: 2, 3:4} - modify(array) - fmt.Println(array) -} -func modify(a [5]int){ - a[1] =3 - fmt.Println(a) -} + [1 2 3] + [1 2 10] +可以看到使用`arr1`对`arr2`赋值操作后,`arr2`是完整的数组复制,对`arr2`的改动不会对`arr1`产生任何影响。 -func main() { - array := [5]int{1: 2, 3:4} - modify(&array) - fmt.Println(array) -} -func modify(a *[5]int){ - a[1] =3 - fmt.Println(*a) -} +同时需要注意,同样类型的数组是可以相互赋值的,不同类型的不行,会编译错误。那么什么是同样类型的数组呢?Go语言规定,**必须是长度一样,并且每个元素的类型也一样的数组,才是同样类型的数组**。 +### 数组作为函数参数 + +在函数间传递变量时,总是以值的方式,如果变量是个数组,那么就会整个复制,并传递给函数,如果数组非常大,比如长度100多万,那么这对内存是一个很大的开销。 + +由于大数组的值拷⻉⾏为会造成性能问题,通常会建议使⽤`slice`,或数组指针,例如: + + func main() { + array := [5]int{1: 2, 3:4} + + modify(&array) + fmt.Println(array) + } + + func modify(a *[5]int){ + a[1] =3 + fmt.Println(*a) + } + +上面的代码传递数组的指针,所以这种情况节省了复制的内存。 +但是要谨慎使用,因为一不小心,就会修改原数组,导致不必要的问题。 +