文章目录
数组
基本认识
数组元素可以通过 索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推(数组以 0 开始在所有类 C 语言中是相似的)。元素的数目(也称为长度或者数组大小)必须是固定的并且在声明该数组时就给出(编译时需要知道数组长度以便分配内存);数组长度最大为 2GB
在内存中,数组中的元素默认会初始化为0
基本使用
下面先看如何进行遍历
go
func test1() {
var arr1 [5]int
for i := 0; i < len(arr1); i++ {
fmt.Println(i, arr1[i])
}
}
另外一种遍历方式是使用range进行遍历,具体如下
go
func test2() {
var arr1 [5]int
for i, j := range arr1 {
fmt.Println(i, j)
}
}
这也是一种遍历的方式,其中i表示的是下标,而j表示的是下标对应数组的值,这点和之前的逻辑是一样的
new创建数组
在Go中,数组的创建是可以使用new来进行创建的,原因在于Go中的数组是一种值类型,而不是像C++中是一个指向首元素地址的指针,参考如下两种创建方式
go
var arr1 = new ([5]int)
var arr2 [5]int
这两种操作的区别就在于,当把一个数组赋值给另外一个的时候,需要再做一次数组的拷贝操作,将内存进行一个拷贝,比如
go
arr2 := *arr1
arr2[2] = 100
这样的话,两个数组就都有了不同的值,之后对于arr2的修改操作是不会影响到arr1的
数组传参
对于数组传参来说,其实说的就是上面的这个逻辑
当函数中,数组作为参数进行传入的时候,就会进行一次数组内存的拷贝操作,函数内部的修改是不会影响函数内部的修改的,如果想要进行修改,需要使用&来进行传递,具体的实现如下所示
go
func t4func1(arr [5]int) {
fmt.Println("t4fun1before", arr)
for i := 0; i < len(arr); i++ {
arr[i] += 3
}
fmt.Println("t4func1after", arr)
}
func t4func2(arr *[5]int) {
fmt.Println("t4fun2before", arr)
for i := 0; i < len(arr); i++ {
arr[i] += 3
}
fmt.Println("t4func2after", arr)
}
func test4() {
var arr1 [5]int
t4func1(arr1)
fmt.Println(arr1)
t4func2(&arr1)
fmt.Println(arr1)
}
输出结果为
text
t4fun1before [0 0 0 0 0]
t4func1after [3 3 3 3 3]
[0 0 0 0 0]
t4fun2before &[0 0 0 0 0]
t4func2after &[3 3 3 3 3]
[3 3 3 3 3]
由此可见,这里是和C++有一点相似的,但是也有一点不同,如果传递指针的话也可以直接进行使用,实际上可以理解为传递的是一种引用
数组常量
如果提前知道了数组的值,那么在创建的时候是可以提前进行初始化的,这点和之前的逻辑一样,不过在写法上有一些创新:
go
func test5() {
arr1 := [5]int{1, 2, 3}
arr2 := [5]int{3: 2, 4: 2}
fmt.Println(arr1)
fmt.Println(arr2)
}
新增了可以在初始化的时候就指定数组下标对应的元素是什么
数组的传参
数组的传参有较高的成本,于是有两种方式可以避免传参的时候带来的拷贝问题
- 传递数组的指针
- 传递数组的切片
使用数组的指针来进行操作实际上前面已经演示过了,而在实际的场景中其实也不会使用数组的指针来进行操作,更多使用的是切片,所以直接看切片
slice切片
定义
切片 (slice) 是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(因此更类似于 C/C++ 中的数组类型,或者 Python 中的 list 类型)。这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索引标识的项不包括在切片内。切片提供了一个相关数组的动态窗口
切片定义后,默认为nil,长度为0
下面演示利用数组生成切片的几种定义方式
go
func test6() {
arr1 := [6]int{0, 1, 2, 3, 4, 5}
// 生成的切片是arr1中,下标[2, 4)对应的内容,也就是2 3
s1 := arr1[2:4]
fmt.Println(s1)
// 还可以这样生成,下标[3, 6)对应的内容,也就是3 4 5
s2 := arr1[3:]
fmt.Println(s2)
// 还可以这样生成,下标[0, 4)对应的内容,也就是0 1 2 3
s3 := arr1[:4]
fmt.Println(s3)
}
传参
在通常进行参数传递的时候,其实会将参数声明为一个切片,当调用函数的时候,就把数组进行分片,然后把切片引用进行传递给函数即可
go
func sum(a []int) int {
res := 0
for _, v := range a {
res += v
}
return res
}
func test8_func(a []int) {
for i, _ := range a {
a[i] = 0
}
}
func test8() {
a := [5]int{1, 2, 3, 4, 5}
fmt.Println(sum(a[:]))
fmt.Println(sum(a[1:]))
test8_func(a[3:])
fmt.Println(a)
}
make分配内存
对于切片来说,想要进行实际的分配还有其他的方式,不一定一定要借助