数组和切片 数组是具有相同 唯一类型 的一组已编号且长度固定的数据项序列(这是一种同构的数据结构)。
数组的初始化 1 2 3 4 5 6 //声明并赋值 var b = [3]int{1,2,3} c := [2]int{1,2} //重新设置设置值 c[0] = 4
示例:
1 2 3 4 5 6 7 8 9 10 11 12 func TestArray(t *testing.T) { var a [3]int t.Log(len(a)) // 3 t.Log(a) //[0 0 0] var b = [3]int{1,2,3} t.Log(b) //[1 2 3] b[0] = 10 b[1] = 20 t.Log(b) //[10 20 3] }
数组的遍历 使用for 遍历数组 或for range 遍历数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 func TestArrayFor(t *testing.T) { arr := [4]int{1,2,3,4} //遍历1 for i:=0;i<len(arr);i++ { t.Logf("index %d = value %d \n",i,arr[i]) } t.Log("================================\n") //遍历2 for index,data := range arr { t.Logf("index %d = value %d \n",index,data) } }
数组的截取 将数组截取成小的数组,通过在数组中的索引的冒号的方式表示切割
arr2 := arr[2:3]
1 2 3 4 5 6 7 8 9 10 11 12 func TestArrayCut(t *testing.T) { arr := [5]string{"你","好","啊","说","啥"} //部分切 arrCut1 := arr[0:3] t.Log(arrCut1) //[你 好 啊] //全部切 arrCut2 := arr[:] //表示全部 t.Log(arrCut2) //[你 好 啊 说 啥] //范围切 arrCut3 := arr[2:] t.Log(arrCut3) //[啊 说 啥] }
数组长度最大为 2GB
切片 数组的长度是固定的,所以在很多场景使用不太方便。 go中提供了切片这种数据类型,长度不固定,并且长度可自动扩容。 切片 (slice) 是对数组一个连续片段的引用,所以切片是一个引用类型。
切片对象内部指向的是一个固定的长度的数组的引用,一旦超过切面的最大容量,引用的数组扩容,既将数组的值拷贝到新数组,然后将引用再指向这个切片。
切片的相关方法 cap() 容量 len() 长度
切片是不能像数组那样通过 == 比较的。
切片的声明 不指定容量的声明 var s []int
指定容量的声明 通过make 函数来创建一个切片
slice := make([]type,length,capacity)
根据数组中创建 数组的切割方式获取的就是一个切片
slice := arr[2:5]
切片的相关方法 切片长度改变
sl = sl[0:len(sl)+1]
注意:改变的是长度而不是容量
1 2 3 4 5 6 7 8 9 func TestSlice(t *testing.T) { s := make([]int,0,2) t.Log(len(s)) //0 t.Log(cap(s)) //2 s = s[0:len(s)+1] t.Log(len(s)) //1 t.Log(cap(s)) //2 }
切片的复制和追加
copy 完成切片的复制操作 append 向切片中追加元素
注意:append 不会在原来的值上修改,需要重新赋值给原切片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func TestSlice(t *testing.T) { s1 := []int{1,2,3,4} s2 := make([]int,4) //注意:第一个参数是dst num := copy(s2,s1) t.Logf("拷贝的数量 %d",num) // 拷贝的数量 4 t.Log(s2) //[1 2 3 4] s2 = append(s2, 5) s2 = append(s2,6) //追加多个 s2 = append(s2,7,7,8) t.Log(s2) }
追加的一些操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 //追加的操作 func TestAppend(t *testing.T) { s1 := []int{1,2,3,4} //对原切片去除一些元素 s2 := append(s1[:1],s1[3]) t.Log(s2) //删除索引为 1 的元素 s3 := append(s1[:1],s1[2:]...) t.Log(s3) s5 := []int{1,2,3,4} //指定位置插入元素 s5 = append(s5[:1],append([]int{10},s5[1:]...)...) t.Log(s5) //[1 10 2 3 4] }
切片的扩容机制 切片的引用的数组的容量是成倍扩容的
1 2 3 4 5 6 7 8 9 10 //追加的操作 func TestSpliceCap(t *testing.T) { var s []int t.Logf("len = %d cap = %d",len(s),cap(s)) for i := 0; i < 30; i++ { s = append(s, i) t.Logf("len = %d cap = %d",len(s),cap(s)) } }
通过输出的结果来看,能够知道内部的数组是成倍扩容的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 type_test.go:259: len = 0 cap = 0 type_test.go:262: len = 1 cap = 1 type_test.go:262: len = 2 cap = 2 type_test.go:262: len = 3 cap = 4 type_test.go:262: len = 4 cap = 4 type_test.go:262: len = 5 cap = 8 type_test.go:262: len = 6 cap = 8 type_test.go:262: len = 7 cap = 8 type_test.go:262: len = 8 cap = 8 type_test.go:262: len = 9 cap = 16 type_test.go:262: len = 10 cap = 16 type_test.go:262: len = 11 cap = 16 type_test.go:262: len = 12 cap = 16 type_test.go:262: len = 13 cap = 16 type_test.go:262: len = 14 cap = 16 type_test.go:262: len = 15 cap = 16 type_test.go:262: len = 16 cap = 16 type_test.go:262: len = 17 cap = 32 type_test.go:262: len = 18 cap = 32 type_test.go:262: len = 19 cap = 32 type_test.go:262: len = 20 cap = 32 type_test.go:262: len = 21 cap = 32 type_test.go:262: len = 22 cap = 32 type_test.go:262: len = 23 cap = 32 type_test.go:262: len = 24 cap = 32 type_test.go:262: len = 25 cap = 32 type_test.go:262: len = 26 cap = 32 type_test.go:262: len = 27 cap = 32 type_test.go:262: len = 28 cap = 32 type_test.go:262: len = 29 cap = 32 type_test.go:262: len = 30 cap = 32 --- PASS: TestSpliceCap (0.00s) PASS Process finished with the exit code 0
数组和切片的主要区别在于切片可自动扩容。并且切片不能比较,数组可以比较.
Map 无序的键值对数据结构容器。
map初始化 声明map,只声明的map为nil 值
var map1 map[int]string
1 2 3 var map1 map[int]string t.Log(map1 == nil) //true
声明并初始化,此时map可以正常赋值
1 2 3 4 map1 := map[int]string{} map1[1] = "1" map1[2] = "2"
初始值的时候指定值
1 2 map1 := map[int]string{1:"1",2:"2"} t.Log(map1)
使用make来初始化 推荐
1 2 3 map1 := make(map[string]string) map1["2"] = "2" t.Log(map1)
指定容量初始化
可以在make的时候指定初始容量,但是 cap 并不能获取目前的容量大小。
1 2 map2 := make(map[string]string,10) t.Logf("map2 len %d",len(map2))
基本操作 map1[1] = 100
delete(map1,1)
data,ok := map1[2]
元素访问会有2个返回值一个是数据,一个是是否存在的标记
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 map1 := make(map[int]int) //添加元素 map1[1] = 10 map1[2] = 20 t.Log(map1) //覆盖元素 map1[1] = 100 t.Log(map1) //删除元素 delete(map1,1) t.Log(map1) //判断元素是否存在 data,ok := map1[2] if(ok){ t.Log(data) }else{ t.Log("不存在") }
map 的遍历 map的遍历只能使用for range来遍历
1 2 3 4 5 6 7 func TestMapFor(t *testing.T) { map1 := map[string]string{"1":"一","2":"二"} for k,v := range map1{ t.Logf("k = %s v = %s \n",k,v) } }
如果只需要value 不需要key 可以使用 **_ ** 表示无用的参数占位符
1 2 3 4 5 6 func TestMapFor(t *testing.T) { map1 := map[string]string{"1":"一","2":"二"} for _,v := range map1{ t.Log(v) } }
map 的切片 map类型的切片的意思是 切片的每个元素都是一个map,类似于java中的 List<Map<K,V>> 这种结构。 需要注意的是对切片内部的每个map 都需要再执行make完成初始化。
1 2 3 4 5 6 7 8 9 10 11 func TestSliceMap(t *testing.T) { s1 := make([]map[int]int,5) map1 := s1[0] t.Log(map1 == nil) //true t.Log(s1) //切片内的map初始化 for i := 0;i< len(s1);i++{ s1[i] = make(map[int]int) } t.Log(s1[0] == nil) //false }
map 排序 map 是没有顺序的,如果想有顺序的获取map中的元素,需要先将key 或 value 拷贝到一个切片,然后对切片排序
根据key排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func TestSortByKey(t *testing.T) { map1 := map[int]int{1:1,2:2,100:100,20:20,40:40,4:4} keys := make([]int,len(map1)) i := 0 for k,_ := range map1{ keys[i] = map1[k] i++ } //对key进行排序 sort.Ints(keys) for _,k := range keys{ t.Log(map1[k]) } }
map 和工厂模式 map的value 可以是一个方法,所以可以通过map来实现一个简单的工厂模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func TestMapFactory(t *testing.T) { map1 := map[int]func(op int)int {} map1[1] = func(op int) int { return op + 1 } map1[2] = func(op int) int { return op + 2 } map1[3] = func(op int) int { return op + 3 } t.Log(map1[1](1)) t.Log(map1[2](1)) t.Log(map1[3](1)) }
不同的key分别有不同的实现
注意:go 中的传输都是值传递,外部的值不会被修改,而map的会被修改时因为传递map 的时候复制的新对象的内部引用是以一个。可以理解为 复制的时候是浅拷贝
Set set 是一个无序的,不可重复的数据结构。在go中是没有set这个数据结构的,不过可以通过map来实现一个set。
一般使用一个value 为bool 的map 来实现set的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func TestSet(t *testing.T) { set := make(map[string]bool) //添加元素 set["1"] = true //size t.Logf("size = %d",len(set)) //是否包含 if set["1"]{ t.Logf("包含 1") }else{ t.Logf("不包含 1") } //删除操作 delete(set,"1") if set["1"]{ t.Logf("包含 1") }else{ t.Logf("不包含 1") } }
因为value 使用bool 类型,所以不用判断值是否存在,值为true 那么一定是存在