Go语言入门到实战——00主目录
在上一讲中我们学习了Go语言的条件循环知识。
一.数组的声明
package typetest
import "testing"
func TestArray(t *testing.T) {
var a [3]int //1.定义一个一维三元素的数组,未进行初始化值均为0
b := [4]int{1, 2} //2.初始化一个数组,赋值b[0]=1,b[1]=2;但是b[2]及以后默认为0
c := [2][2]int{{1, 2}, {3, 4}} //3.初始化定义多维数组
d := [...]int{1, 2, 3, 4} //4.不知道具体多少个元素时可以打三个点
t.Log(a, b, c, d)
}
二.数组的遍历
当然遍历数组的方式也需要说明一下:(一下两种方案等价
)
package arrtest
import "testing"
func TestArray(t *testing.T) {
var a = [...]int{1,2,3,4}
for idx, e := range a {
t.Log(idx, e)
}
}
package arrtest
import "testing"
func TestArray(t *testing.T) {
var a = [...]int{1, 2, 3, 4}
for i := 0; i < len(a); i++ {
t.Log(i, a[i])
}
}
当然对于第一种写法我们需要考虑一个问题,就是当我们不需要idx时,我们可以这么写
//使用_进行占位,表示我们不关心idx,d但是下面的_不能写idx,因为这样后面不使用idx就会报错了
func TestArray(t *testing.T) {
var a = [...]int{1,2,3,4}
for _,e := range a {
t.Log(e)
}
}
三.切片
go语言的对数组进行切割可以得到切片的一般格式如下:
a[开始索引,结束索引) //注意是左闭右开
例子演示:
package arrtest
import "testing"
func TestArray(t *testing.T) {
var a = [...]int{1, 2, 3, 4}
t.Log(a[1:2])
t.Log(a[1:len(a)])
t.Log(a[:3])
t.Log(a[2:])
}
这里请不要误以为是和python的切片一样了,比如下面的负数写法就不支持的
a[-1:],a[:-1]等等都不支持
这里我们需要注意的是数组和切片在go里面是不同的概念,数组的长度的容量都是不可变,而切片是可变的,关键是记住数组和切片可以看作是两种不同的'变量类型'
下面我们看一下类型的输出:
package arrtest
import (
"reflect"
"testing"
)
func TestArray(t *testing.T) {
a := [...]int{1, 2, 3, 4}
t.Log(len(a), cap(a))
t.Log(reflect.TypeOf(a))
t.Log(reflect.TypeOf(a[1:]))
}
从上面我们可以看到,数组类型是[4]int
,而切片类型是[]int
,需要仔细理解与区分
上面我们介绍了从数组获取切片的方法,接下来我们讲解一下切片本身的声明方案。
package typetest
import "testing"
func TestArray(t *testing.T) {
//1.声明1,定义一个切片类型
var s0 []int
t.Log(len(s0), cap(s0)) //切片的长度和容量
s0 = append(s0, 1) //切片可以添加数据
t.Log(len(s0), cap(s0)) //切片的长度和容量
//2.声明2,定义一个空元素的切片类型
s1 := []int{}
t.Log(len(s1), cap(s1)) //切片的长度和容量
//3.声明3,定义一个有初始元素的切片类型
s2 := []int{1, 2, 3}
t.Log(len(s2), cap(s2))
//4.使用make构造切片,可以指定长度和容量
s3 := make([]int, 3, 4)//长度为3,容量为4
t.Log(len(s3), cap(s3))
t.Log(s3[2])//初始化前三个元素为0,而第四个没有初始化是不可以访问的
t.Log(s3[3])
}
接下来研究一下切片的容量增长的规律:
package typetest
import "testing"
func TestArray(t *testing.T) {
var s []int = []int{}
for i := 1; i <= 10; i++ {
s = append(s, i) //必须接受返回值,否则相当于定义了一个新的变量但是未使用
//底层的做法(容量不足时)是会开辟新的连续存储空间,然后
//将原有的数据拷贝到新的地址空间去,然后切片的初始地址
//也会发送变化,所以s需要重新赋值
t.Log(len(s), cap(s))
}
}
从上面我们可以看出最开始插入第一个元素容量变为1了,而当往后面一个个插入时,超过容量便会乘以2.接下来我们需要知道的是切片的存储共享结构
两个切片共享了同一块区域,len的大小是可以直接知道的,那个cap容量的大小就是从起始位置到后面末端的长度,因为已经开辟了空间,可以接着放数据而不需要开辟新的空间.下面我们来验证一下:
package typetest
import "testing"
func TestArray(t *testing.T) {
months := []string{"","Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
slice1 := months[4:7]
slice2 := months[6:9]
t.Log(len(slice1), cap(slice1))
t.Log(len(slice2), cap(slice2))
}
四.数组和切片的比较
//记住两点
1.数组是不可扩增容量的,而切片是可以的
2.数组可以进行比较,而切片是不可以的
上面两点留给读者去理解和测试