Go基础之数组与切片
一.数组
- 数组的声明
方式一 var 声明
var arr1 [5]int //规定大小,不需赋初值
方式二 := 声明 需要赋初值
arr2 := [3]int {0,0,0} //采用快速赋值符时,规定数组大小,且需要给数组赋初值
arr3 := [...]int{1,2,3,4,5,6} //通过三个点,让编译器自动计算数组的大小
- 数组的遍历
使用"range"关键字,可以同时获得数组元素的下标和值
for i := 0; i<len(arr3); i++ { //方式1
fmt.Println(arr3[i])
}
for i := range arr3 { //方式2 只获得下标
fmt.Println(arr3[i])
}
for _, v := range arr3 { //方式3 只获得值
fmt,Println(v)
}
for i, v := range arr3 { //方式4 同时获得下标和值
fmt,Println(i, v)
}
go语言中的"range"
- 意义明确,美观
- C++中没有类似操作
- Java/Python 只能for each 元素的值,不能同时获得下标和值
- 注意,go语言中的数组是值类型
- 数组必须规定其大小,[10]int 和[20]int 是不同的数据类型
- func f(arr [10]int) 会拷贝数组,这一点与其他大多语言都不同,其他语言的数组一般多为引用传递
- go语言中一般不直接使用数组,而是使用切片
二.切片(slice)
- 初识切片
arr := [...]int{0,1,2,3,4,5,6,7}
s := arr[2:6] //这里的s 就是一个切片,其值为[2,3,4,5],切片内的范围是左闭右开的
s1 := arr[:6]
s2 := arr[2:]
s3 := arr[:] //s1,s2,s3 均是切片
另外,不加长度的数组就是一个slice
func f(s [ ]int) //这里的s是一个slice
- slice本身是没有数据的,slice是对底层数组的一个view,slice是按引用传递的
- 对slice操作实际上就是对slice对应的底层数组的操作
package main
import (
"fmt"
)
func updateArr(s []int){
s[0] = 100
fmt.Println(s)
}
func main(){
arr := [8]int{0,1,2,3,4,5,6,7}
s1 := arr[2:6]
s2 := arr[:]
fmt.Println("Arr:",arr)
fmt.Println("s1:",s1)
fmt.Println("s2:",s2)
fmt.Println("After update s1:")
fmt.Print("s1:")
updateArr(s1)
fmt.Println("Arr:",arr)
fmt.Println("After update s2:")
fmt.Print("s2:")
updateArr(s2)
fmt.Println("Arr:",arr)
}
输出结果:Arr: [0 1 2 3 4 5 6 7]
s1: [2 3 4 5]
s2: [0 1 2 3 4 5 6 7]
After update s1:
s1:[100 3 4 5]
Arr: [0 1 100 3 4 5 6 7]
After update s2:
s2:[100 1 100 3 4 5 6 7]
Arr: [100 1 100 3 4 5 6 7]
- slice的"reslice"操作
package main
import (
"fmt"
)
func main(){
arr := [8]int{0,1,2,3,4,5,6,7}
//reslice
s := arr[:]
fmt.Println(s)
s = s[2:6] //注意 这里是"="而不是":="
fmt.Println(s)
s = s[1:3]
fmt.Println(s)
}
输出结果:[0 1 2 3 4 5 6 7]
[2 3 4 5]
[3 4]
- slice是可以扩展的 ,扩展只能向后扩展,而不能向前扩展
- 每个slice都是对其所对应的数组的一个view
package main
import (
"fmt"
)
func main(){
arr := [8]int{0,1,2,3,4,5,6,7}
//extend
s1 := arr[2:6]
s2 := s1[3:5] //s2即s1[3],s1[4], 但这里s1中只有4个元素,不存在s1[4], 若单独 fmt.Println(s1[4]) 会报错
fmt.Println(s1)
fmt.Println(s2)
}
但是,输出结果:[2 3 4 5]
[5 6]
- slice的实现,对slice的len和cap的理解
- slice中,s[i] 不可超越其len
- slice的扩展范围不能超过其cap 即s[i:cap]
- 可以通过len(s), cap(s)来查看slice的len和cap值
- 用append()向slice添加元素, s = append(s,val)
- 向slice添加元素时,如果超过其cap,系统会重新分配一个更大的底层数组,原来的底层数组如果没有再被使用就会被回收掉,新的cap为原来cap的两倍
- 由于是值传递,所以必须接受append()的返回值
- 添加元素时slice的cap有可能改变,cap改变则意味则新的底层数组的出现
- slice始终操作的都是底层数组中的数据,slice本身没有数据,故append改变的也是底层数组,如果append没有超出其cap,则是底层数组中元素的替换
package main
import (
"fmt"
)
func main(){
arr := [...]int{0,1,2,3,4,5,6,7}
//append
s1 := arr[2:6]
fmt.Println("Arr:",arr)
fmt.Println("s1:",s1)
s1 = append(s1,10)
fmt.Println("After first append:")
fmt.Println("s1:",s1)
fmt.Println("arr:",arr)
s1 = append(s1,11)
fmt.Println("After second append:")
fmt.Println("s1:",s1)
fmt.Println(cap(s1))
fmt.Println("arr:",arr)
s1 = append(s1,12)
fmt.Println("After third append:")
fmt.Println("s1:",s1)
fmt.Println(cap(s1))
fmt.Println("arr:",arr)
}
输出结果:
Arr: [0 1 2 3 4 5 6 7]
s1: [2 3 4 5]
After first append:
s1: [2 3 4 5 10]
arr: [0 1 2 3 4 5 10 7]
After second append:
s1: [2 3 4 5 10 11]
6
arr: [0 1 2 3 4 5 10 11]
After third append:
s1: [2 3 4 5 10 11 12]
12
arr: [0 1 2 3 4 5 10 11]
- go语言中,每声明一个变量,系统都会给它创建一个"Zero value"
- Zero value of slice is "nil"
- 实际操作中,slice的几种创建方式:
- 方式一
var s1 [ ]int
- 方式二
s2 := [ ]int {1,2,3,4}
这行代码实行了两步操作:
1> 创建了一个底层数组 [...]int{1,2,3,4}
2> 将底层数组的view赋值给切片s2
- 方式三
s3 := make([ ]int, len)
- 方式四
s4 := make([ ]int, len, cap)
- slice的copy操作
copy(s1, s2) //将s2中的元素copy到s1中
- slice 的delete操作
1> 删除中间某个元素
s = append(s[:5], s[6:]...) //删除了s中的s[5]
2> 删除头或尾
s 的头:s[0]
s 的尾:s[len(s)-1]
删除头操作: s = s[1:]
删除尾操作:s = s[:len(s)-1]