文章目录
2.1 数组
go也是有数组了,接下来我们学习一个数组。
2.1.1 定义数组
go定义数组有几种方式:
func main() {
// go数组的定义
var arr1 [3]bool // 没有赋初值 但是go默认会赋初值
arr2 := [3]int{1, 2, 3} // 这是又初值
arr3 := [...]int{1,2,3,4,5} // 这个是根据后面定义个数来确定数组个数
var arr4 [4][5]int // 二维数组,4行5列
fmt.Println(arr1, arr2, arr3, arr4)
return
}
go的数组,也跟别的数组不一样,是个数在前面,后面加类型,比较容易跟别的语言搞混。
go也是支持二维数组的,二维数组第一个是多少行,后面是多少列
[false false false] [1 2 3] [1 2 3 4 5] [[0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0] [0 0 0 0 0]]
2.1.2 数组遍历
接下来我们看看数组的遍历,
- 常规方式
for i:=0; i<len(arr2); i++ {
fmt.Println(arr2[i])
}
这种根据长度的遍历方式是我们常规的操作。
- range
for i, v := range arr3 {
fmt.Println(i, v)
}
go提供了一个关键字,range,就是遍历各个容器的值的,不仅是数组,还有后面的切片和map。而且range的返回值还是有点意思,返回两个值,第一个是下标,第二个才是数组的值。
2.1.3 数组作为函数参数
那我们来看看数组作为函数参数的时候,是怎么传参的:
- 值传递
func funcarr1(arr [3]int) { // [3]int 是一个类型,不存在跟c一样的只传首地址
arr[0] = 100
}
func main() {
// go数组的定义
var arr1 [3]bool
arr2 := [3]int{1, 2, 3}
arr3 := [...]int{1,2,3,4,5}
var arr4 [4][5]int // 二维数组,4行5列
fmt.Println(arr1, arr2, arr3, arr4)
for i:=0; i<len(arr2); i++ {
fmt.Println(arr2[i])
}
funcarr1(arr2)
for i, v := range arr2 {
fmt.Println(i, v)
}
return
}
根据打印出来的结果,明显这个数组就是传值,这个跟我们c/c++是一样的,如果这样传就是直接传值。
那如果这个数组很大,那拷贝是不是很难,所以是存在用数组指针的:
- 指针传递
func funcarr2(arr *[3]int) {
arr[0] = 100
}
这个打印的结果明显是修改了,所以go也是可以传数组的。
但是go会用数组么,其实在go语言中,一般是不用数组的,只会用切片。
2.2 切片
go的大名鼎鼎的切片,其实我学了切片,感觉有点像ArrayList,但是还是不同,不过可以借助ArrayList来帮助我们学习切片也是有意义的。
2.2.1 切片的引入
arr5 := [...]int{0,1,2,3,4,5,6,7,8,9}
fmt.Println("s := [2:6]", arr5[2:6])
fmt.Println("s := [:6]", arr5[:6])
fmt.Println("s := [2:]", arr5[2:])
fmt.Println("s := [:]", arr5[:])
定义一个arr5的数组,然后可以用[]进行各种切片,这个名字起的真是有意思。
打印出来的结果:
s := [2:6] [2 3 4 5]
s := [:6] [0 1 2 3 4 5]
s := [2:] [2 3 4 5 6 7 8 9]
s := [:] [0 1 2 3 4 5 6 7 8 9]
跟我们思路的一样,是感觉下标的切片。
2.2.2 切片做为函数参数
上面我们是写了数组做为函数参数,因为数组的类型是需要
func funcarr3(arr []int) { // 不用限制类型
arr[0] = 100
}
func main() {
arr5 := [...]int{0,1,2,3,4,5,6,7,8,9}
s := arr5[2:6]
fmt.Println(s)
funcarr3(s)
fmt.Println(s)
return
}
切片传过去的时候就不需要大小,并且切片作为函数参数,传的是引用,所以就是函数内部可以修改数组中的值。
[2 3 4 5]
[100 3 4 5]
本来刚刚想用数组作为参数,能不能给切片传值,但是发现还是不行,go语言的类型限制的很死。
2.2.3 切片的扩展
老师出了一道比较难的题:
arr6 := [...]int{0,1,2,3,4,5,6,7}
s1 := arr6[2:6]
s2 := s1[3:5]
fmt.Println(s1, s2)
s1和s2的值,直接打印出来:
[2 3 4 5] [5 6]
这样我们就看到s2是可以取到值的,为啥会这样,其实这个切片是有一个len,和一个cap的,也就是这个切片底层实现是有一个最大容量cap,还有就是一个我们有效数据len,我们可以修改代码,打印出来看看:
arr6 := [...]int{0,1,2,3,4,5,6,7}
s1 := arr6[2:6]
s2 := s1[3:5]
fmt.Printf("s1=%v len(s1)=%d cap(s1)=%d\n", s1, len(s1), cap(s1))
fmt.Printf("s2=%v len(s2)=%d cap(s2)=%d\n", s2, len(s2), cap(s2))
打印结果:
s1=[2 3 4 5] len(s1)=4 cap(s1)=6
s2=[5 6] len(s2)=2 cap(s2)=3
这样是不是很像是一个ArrayList,其实是有一个容量的,也有一个有效长度,所以切片在给数据做切片的时候,是保留了向后扩展的能力,这样s2才能取出值。
如果使用append添加元素的时候,如果超过原来数组的cap,就会从新分配一个新更大的底层数组,然后把值拷贝过去,原来的数组如果没有人使用,就由go垃圾回收掉。
2.2.4 直接定义切片
我们一般在使用操作中,应该不会先定义一个数组,然后在改成切片的,我们是可以直接定义切片的:
var s3 []int // 没有值,值是nil
fmt.Println(s3)
s3 = append(s3, 1)
s4 := []int{3,4,5}
fmt.Println(s4)
// 知道长度,需要定义一个切片
s5 := make([]int, 10)
fmt.Println(s5)
// 需要定义cap也是可以的
s6 := make([]int, 10, 20)
fmt.Println(s6)
直接定义的切片有这么4种方式,不过第3种方式我们会经常用,这样看看是不是更像ArrayList了。
2.2.5 切片操作
通过菜鸟教程,我们知道除了append()外还有copy()函数。
其他函数目前我也不知道,哈哈哈哈。
2.3 map
go也是又map的,接下来学习学习map。
2.3.1 定义
还是直接来学习一个map的定义:
m := map[string]string {
"name" : "aaa",
"course" : "golang",
"site" : "immoc",
}
fmt.Println(m)
mm := map[string]map[string]string {
"name" : m,
}
fmt.Println(mm)
m2 := make(map[string]int)
m3 := make(map[string]int, 10)
fmt.Printf("m2=%v len(m2)=%d\n", m2, len(m2))
fmt.Printf("m3=%v len(m3)=%d\n", m3, len(m3))
上面是map定义的方式,map可以直接定义,也可以使用make,不过使用make是不能制定大小的,跟切片不一样,map是插入的时候有值了,自然就有值了。
2.3.2 遍历
map遍历应该到这里了,都知道了,是的,map遍历就使用range。
for k, v := range m {
fmt.Println(k, v)
}
这里就不介绍了。
2.3.3 操作
我们尝试一下删除操作:
m["name"] // 获取值
delete(m, "name") // 删除
这个也没啥难度的
2.3.4 map的key
-
map使用哈希表,key必须可以比较相等
-
除了slice,map,function的内建类型都可以作为key
-
Struct类型不包含上述字段,有可以作为key
2.3.5 示例
寻找最长不含有重复字符的字串:
(这个之后在写,哈哈哈)
2.4 字符和字符串
2.4.1 rune
rune相等与其他语言的char,因为需要兼容Unicode编码,所以类型是int32,这样中文也可以支持。
ss := "hello world 你好,世界"
for i, c := range []rune(ss) {
fmt.Printf("(i=%d c=%c) ", i, c)
}
运行结果:
(i=0 c=h) (i=1 c=e) (i=2 c=l) (i=3 c=l) (i=4 c=o) (i=5 c= ) (i=6 c=w) (i=7 c=o) (i=8 c=r) (i=9 c=l) (i=10 c=d) (i=11 c= ) (i=12 c=你) (i=13 c=好) (i=14 c=,) (i=15 c=世) (i=16 c=界)
go语言就可以直接打印出中文,如果跟其他语言一样,强转成[]byte也是可以的。
2.4.2 字符串操作
-
使用range遍历pos,rune对
-
使用utf8.RuneCountInString获取字符数量(支持中文)
-
使用len获取字节长度(按字节)
-
使用[]byte获得字节
2.4.3 其他字符串操作
-
Fields,Split,Join
-
Contains,Index
-
ToLower,ToUpper
-
Trim,TrimRight,TrimLeft