五、集合类型
5.1 数组
数据定义
func defArray() {
//定义数组,默认赋值0
var arr1 [5]int
fmt.Println("init val of arr1 =",arr1)
arr1=[5] int {1,3,4,5}
fmt.Println(arr1)
//定义数组并赋予初始值
var arr2 = [3]int{1, 3, 4}
arr3 := [3]int{13, 3, 4}
fmt.Println(arr2, arr3)
// 定义二位数组
arr4 := [3][4]int{{1, 2, 3, 4}, {2, 4, 5, 5}, {3, 4, 5, 4}}
fmt.Println(arr4)
//不固定长度数组
arr5 := [...]int{1, 3, 4}
fmt.Println(arr5)
}
数据遍历
下划线可以用来你做参数占位,省略参数
func printArray() {
arr := [3]int{13, 3, 4}
for i := range arr {
fmt.Println(arr[i])
}
fmt.Println("---------------")
//打印index,value
for i, v := range arr {
fmt.Println(i, v)
}
fmt.Println("---------------")
//打印value,_用于省略变量
for _, v := range arr {
fmt.Println(v)
}
fmt.Println("---------------")
//不常用,for循环便利
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}
数组值传递(go特殊)
- 数组是一种值类型,调用func f(arr[10] int)会拷贝数组
- 不同长度的数组是不同类型,长度3的数组不能接收长度2的数组。
- 数值也是值传递,需通过指针实现引用传递
//1.只能接受长度为3的数组
//2. 值传递而非引用长度
func valTransferArray(arr [3]int) {
arr[0] = 10
fmt.Println(arr)
}
//1.只能接受长度为3的数组
//2. 值传递而非引用长度
func pointerArray(arr *[3]int) {
arr[0] = 10
fmt.Println(arr)
}
func main() {
arr := [3]int{3, 4, 5}
valTransferArray(arr)
//数组时值传递,所以数组并没有改变
fmt.Printf("after %s", arr)
pointerArray(&arr)
fmt.Printf("afterpointer %s", arr)
}
使用指针可以实现引用传递
[10 4 5]
after [%!s(int=3) %!s(int=4) %!s(int=5)]&[10 4 5]
afterpointer [%!s(int=10) %!s(int=4) %!s(int=5)]
5.2 动态数组·切片 slice
slice和array很相似,但使用时有巨大差异
slice定义
- 可以通过slice=nil判断是否为空切片
- 不指定cap时,默认cap=len
func defSlice() {
//定义slice
var s1 [] int
fmt.Println(&s1)
fmt.Println(s1==nil) //true ,可以用nil判断slice是否是空的
fmt.Printf("len= %d val=%v \n",len(s1),s1)
//定义slice并赋初值,
s2:=[]int{1,3,4}
fmt.Printf("s2 leng=%d cap=%d val=%v \n",len(s2),cap(s2),s2)
//定义slice并开辟空间(type,leng,cap),但不赋值
s3:=make([]int,3,5)
fmt.Printf("s3 leng=%d cap=%d val=%v \n",len(s3),cap(s3),s3)
}
切片切割
func sliceArray() {
//半开半闭区间,包括开始,不包括结尾
arr := [...]int{2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(arr[2:4])
fmt.Println(arr[:4])
fmt.Println(arr[4:])
}
切片扩展
func appendSlice(){
s1:=make([]int,3,5)
fmt.Printf("s1 leng=%d cap=%d val=%v \n",len(s1),cap(s1),s1)
s1=append(s1,1)
fmt.Printf("s1 leng=%d cap=%d val=%v \n",len(s1),cap(s1),s1)
s1=append(s1,2)
fmt.Printf("s1 leng=%d cap=%d val=%v \n",len(s1),cap(s1),s1)
//超出slice的cap时,会按照2*cap自动扩容
s1=append(s1,3)
fmt.Printf("s1 leng=%d cap=%d val=%v \n",len(s1),cap(s1),s1)
s2:=append(s1,3,4)
fmt.Printf("s2 leng=%d cap=%d val=%v \n",len(s2),cap(s2),s2)
}
增删改查
func testSlice2() {
s2 := []int{23, 4, 3, 5}
s3 := make([]int, 10, 32)
//复制slice
copy(s3, s2)
printSlice(s2)
printSlice(s3)
//删除第N个元素
s2 = append(s2[:1], s2[2:]...)
printSlice(s2)
//
}
slice和array关系
slice是数组的切片,对array的视图和引用,slice使用引用传递
注:slice是array的一个视图,本身没有数据
通过slice可以引用传递改变数组
arr := [...]int{1, 3, 43}
sliceTranArray(arr[:])
fmt.Println("after", arr)
//使用slice传递数组
func sliceTranArray(array []int) {
array[0] = 100
fmt.Println(array)
}
切片原理(重要)
切片是array的视图,包含了三部分
- ptr切片的起点引用
- 切片长度
- cap扩展区域
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7f5CakVx-1648100093923)(E:/youdao/微信截图_20211128215021.png)]
func reSlice() {
arr := [...]int{0,1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
fmt.Println(s1)
fmt.Println(s2)
}
结果
[2 3 4 5]
# s1指向的是arr的引用,引用中包含扩展区
# s2指向的也是arr的引用,3,5获取了扩展区内容
[5 6]
如果想slice添加的元素超过了cap的上线,系统就会创建新的数组,将原来的数组就会垃圾回收掉。
slice扩容机制
func printSlice(slice []int) {
//打印slice的实际长度和扩展长度
fmt.Println(len(slice), cap(slice))
}
func testSlice() {
var s1 = []int{} //zero value is nil
for i := 0; i < 100; i++ {
s1 = append(s1, 2*i+1)
printSlice(s1)
}
printSlice(s1)
}
slice达到16后是指数扩容的
1 1
2 2
3 4
4 4
5 8
6 8
7 8
8 8
9 16
10 16
11 16
12 16
13 16
。。。
60 64
61 64
62 64
63 64
64 64
65 128
66 128
67 128
。。。
100 128
Process finished with the exit code 0
5.3 Map(key-value)类型
- map的key是无序的,可以通过slice转换排序
- map使用hash表,key必须可以hash
- slice,map,function以外的类型都可以作为key。自定义类型包括三者之一不能作为key
map定义
空map的长度都是0,map本身=nil可以判断map不包含元素
//方式1:仅声明一个map,map[key-type]value-type,但不赋值
//tip:可以通过nil判断map是否包含元素
var map1 map[string]string
fmt.Println("map1==nil ",map1==nil)
//方式2:make方式声明map,并制定初始size
map2:=make(map[int]string,1)
fmt.Println("size before",len(map2),map2) //0
map2[0]="java"
map2[1]="golang"
map2[2]="python"
fmt.Println("size after",len(map2),map2) //3
//方式3:声明map同时赋初值
map3:=map[string]string{
"name": "zhangsan",
"location": "shagnhai",
}
fmt.Println(map3)
//定义并赋值
m := map[string]string{
"name": "zhangsan",
"location": "shagnhai",
}
fmt.Println(m)
增删改查
使用for遍历,结果无序
//key是无需的,hashmap结构
for k, v := range m {ß
fmt.Println(k, v)
}
通过m[key]获取元素,可以通过下面方法判断是否存在
fmt.Println(m["name"])
//如果key不存在获取到zerovalue(这里是空字符串)
fmt.Println(m["nameddd"])
if s, ok := m["name"]; ok {
fmt.Println(s)
} else {
fmt.Println("key not exist")
}
delete(key) 删除元素
key不存在,删除无效,不报错
//删除元素
fmt.Println("delete----")
delete(m, "name")
fmt.Println(m)
修改map内容,map作为参数可以理解为引用传递
//修改map
changeVal(m)
fmt.Println(m)
//map是引用传递,而非值传递
func changeVal(maptmp map[string]string){
maptmp["New"]="new member"
}
完整代码
func crudMap() {
//定义并赋值
m := map[string]string{
"name": "zhangsan",
"location": "shagnhai",
}
fmt.Println(m)
//遍历:key是无需的,hashmap结构
for k, v := range m {
fmt.Println(k, v)
}
//打印单个元素
fmt.Println(m["name"])
//如果key不存在获取到zerovalue(这里是空字符串)
fmt.Println(m["nameddd"])
if s, ok := m["nameddd"]; ok {
fmt.Println(s)
} else {
fmt.Println("key not exist")
}
//删除元素
fmt.Println("delete----")
delete(m, "nme")
fmt.Println(m)
//修改map
changeVal(m)
fmt.Println(m)
}
5.4 rune
- rune相当于golang的char类型
- utf8.RunecountInString获取字符数
func runeTest() {
str := "Yes,我爱中国!" //utf-8编码,英语1个byte,汉子3bytes
fmt.Println(len(str))
for i, b := range []byte(str) {
//长度为17位,等于len结果
fmt.Printf(" (%d, %X) ", i, b)
}
fmt.Println("------------ch-------")
for i, ch := range str {
fmt.Printf(" (%d, %X) ", i, ch)
}
fmt.Println("-------------rune array")
for i, r := range []rune(str) {
fmt.Printf(" (%d, %X) ", i, r)
}
}
结果
str转换成rune数组后,可以得到业务上的含义。这个过程是内部创建一个rune数组后转换的结果
17
(0, 59) (1, 65) (2, 73) (3, 2C) (4, E6) (5, 88) (6, 91) (7, E7) (8, 88) (9, B1) (10, E4) (11, B8) (12, AD) (13, E5) (14, 9B) (15, BD) (16, 21) ------------ch-------
(0, 59) (1, 65) (2, 73) (3, 2C) (4, 6211) (7, 7231) (10, 4E2D) (13, 56FD) (16, 21) -------------rune
(0, 59) (1, 65) (2, 73) (3, 2C) (4, 6211) (5, 7231) (6, 4E2D) (7, 56FD) (8, 21)