Skip to content

Commit

Permalink
udpate note about go array
Browse files Browse the repository at this point in the history
  • Loading branch information
WilberTian committed Dec 28, 2017
1 parent 4bd951a commit 0548868
Showing 1 changed file with 92 additions and 40 deletions.
132 changes: 92 additions & 40 deletions 02.Go数组/Go数组.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -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)
}

上面的代码传递数组的指针,所以这种情况节省了复制的内存。
但是要谨慎使用,因为一不小心,就会修改原数组,导致不必要的问题。

0 comments on commit 0548868

Please sign in to comment.