Golang基础之数组和切片
1、数组概念
数组是类型相同的元素集合,比如整数:1,39,90,100的集合就构成了一个数组,Go不允许在数组中混合使用不同类型的元素(比如整数和字符串)
1.1、数组声明
var 变量名 [size]类型
数组声明方式有太多了,下面一一介绍
简单声明式
func main(){
var a [2]int // 定义一个长度为2的数组
fmt.Println(a)
}
上面var a [2]int
声明了一个长度为2,类型为整型的数组,数组中的所有元素都被自动赋值到元素类型的0值,运行上面程序,输出为[0 0]
。
快速声明式
func main(){
a1 := [2]int{13,33}
fmt.Println(a1)
var a2 [3]int = [3]int{1,2,3}
fmt.Println(a2)
}
上面这种方式,可以在初始化数组的时候顺便给赋值,赋值不一定就要跟指定的长度一样。
指定下标初始化值
func main(){
a := [6]int{4:100,5:300}
fmt.Println(a)
}
1.2、数组赋值
我们除了能够声明指定长度的数组和指定类型以外还能够给数组赋值,如下:
func main(){
var a [2]int // 定义一个长度为2的数组
a[0] = 13 // 数组索引开始值为0
a[1] = 33
fmt.Println(a)
}
a[0]
为数组中的第一个元素,执行程序输出[13 33]
注意:数组长度是类型的一部分。也就是说不同长度的数组,就为不同类型的数组,它们之间不能赋值
1.3、数组长度
基于内置函数len
可求数组长度
func main(){
a := [5]int{1,2,3,6,7}
fmt.Println(len(a)) // 5
}
1.4、数组遍历
通过for
循环可以遍历数组元素
第一种方法:常规方法
func main(){
a := [5]int{1,2,3,6,7}
for i := 0; i < len(a); i++ {
fmt.Printf("a[%d]=%d\n",i,a[i])
}
}
// 遍历结果
a[0]=1
a[1]=2
a[2]=3
a[3]=6
a[4]=7
第二种方法:推荐使用
func main(){
a := [5]int{1,2,3,6,7}
// var index,value int
for index,value := range a{ // index:数组索引,value:数组元素值
fmt.Printf("a[%d]=%d\n",index,value)
}
}
// 遍历结果
a[0]=1
a[1]=2
a[2]=3
a[3]=6
a[4]=7
1.5、二维数组
我们可以根据多个维度去定义数组,例如常见的二维数组
func main(){
var a [3][2]int
a[0][0] = 10
a[0][1] = 20
a[1][0] = 30
a[1][1] = 30
a[2][0] = 30
a[2][1] = 30
fmt.Println(a)
}
// 运行结果
[[10 20] [30 30] [30 30]]
那,如何对数组进行遍历尼?看下面
func main(){
var a [3][2]int
a[0][0] = 10
a[0][1] = 20
a[1][0] = 30
a[1][1] = 30
a[2][0] = 30
a[2][1] = 30
// 第一种循环
for i :=0; i < 3;i ++ {
for j := 0;j < 2; j++ {
fmt.Printf("%d ",a[i][j])
}
fmt.Println()
}
// 第二种循环
for i,val := range a {
for j,val2 := range val {
fmt.Printf("(%d,%d)=%d ",i,j,val2)
}
}
// 运行结果
10 20
30 30
30 30
(0,0)=10 (0,1)=20
(1,0)=30 (1,1)=30
(2,0)=30 (2,1)=30
2、切片概念
切片指向了一个底层的数组,切片的长度就是它元素的个数。切片的容量是底层数组从切片的第一个元素到最后一个元素的数量。
切片的本质:切片就是一个框,框住了一块连续的内存,属于引用类型,真正的数据都是保存在底层数组里。
2.1、切片定义
定义切片不需要指定元素长度,它会自动根据元素个数来动态定义,而一个没有元素的切片则为nil
var s1[]int // 定义一个存放int类型元素的切片
var s2[]string // 定义一个存放string类型元素的切片
fmt.Println(s1,s2)
fmt.Println(s1 == nil) // true
fmt.Println(s2 == nil) // true
初始化切片:定义了切片后需要将其初始化值
s1 = []int{1,2,3}
s2 = []string{"张家口","花果山","通天河"}
fmt.Println(s1,s2)
2.2、切片长度和容量
s1 = []int{1,2,3}
s2 = []string{"张家口","花果山","通天河"}
fmt.Printf("len(s1):%d cap(s1):%d\n",len(s1),cap(s1))
fmt.Printf("len(s2):%d cap(s2):%d\n",len(s2),cap(s2))
2.3、数组切片
可以基于数组的基础上进行切片
a1 := [...]int{1,3,5,7,9,11,13}
s3 := a1[0:4] // [1 3 5 7] 基于一个数组切割,左包含右不包含,左闭右开
fmt.Println(s3)
s4 := a1[1:6]
fmt.Println(s4)
s5 := a1[:4] // 从索引0开始至4 [0:4] [1 3 5 7]
s6 := a1[3:] // 从索引3开始至最后,包含索引3 [7 9 11 13]
s7 := a1[:] // 从索引0开始至最后,取所有
fmt.Println(s5,s6,s7)
// 切片的容量是指底层数组的容量
fmt.Printf("len(s5):%d cap(s5):%d\n",len(s5),cap(s5))
// 底层数组从切片的第一个元素指向到最后的元素数量
fmt.Printf("len(s6):%d cap(s6):%d\n",len(s6),cap(s6))
2.4、向切片添加元素
append 的结果是一个包含原 slice 所有元素加上新添加的元素的 slice,如果底层数组太小,而不能容纳所有值时,会分配一个更大的数组。 返回的 slice 会指向这个新分配的数组。
package main
import "fmt"
func main(){
a = append(a,0) // 往切片追加元素 0
printSlice("a",a) // a len=1 cap=1 [0]
a = append(a,1,2,3,4,5) // 可以追加N个元素
printSlice("a",a) // a len=6 cap=6 [0 1 2 3 4 5]
}
func printSlice(s string,x []int) {
fmt.Printf("%s len=%d cap=%d %v \n",
s,len(x),cap(x),x)
}