golang简明入门进阶指南02 数组切片map类型的基础使用

Posted 如何在5年薪百万

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang简明入门进阶指南02 数组切片map类型的基础使用相关的知识,希望对你有一定的参考价值。

五、集合类型

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]int1, 3, 4
	arr3 := [3]int13, 3, 4
	fmt.Println(arr2, arr3)
	// 定义二位数组
	arr4 := [3][4]int1, 2, 3, 4, 2, 4, 5, 5, 3, 4, 5, 4
	fmt.Println(arr4)

	//不固定长度数组
	arr5 := [...]int1, 3, 4
	fmt.Println(arr5)

数据遍历

下划线可以用来你做参数占位,省略参数

func printArray() 

	arr := [3]int13, 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特殊)

  1. 数组是一种值类型,调用func f(arr[10] int)会拷贝数组
  2. 不同长度的数组是不同类型,长度3的数组不能接收长度2的数组。
  3. 数值也是值传递,需通过指针实现引用传递
//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]int3, 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:=[]int1,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 := [...]int2, 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 := []int23, 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 := [...]int1, 3, 43
	sliceTranArray(arr[:])
	fmt.Println("after", arr)

//使用slice传递数组
func sliceTranArray(array []int) 
	array[0] = 100
	fmt.Println(array)


切片原理(重要)

切片是array的视图,包含了三部分

  1. ptr切片的起点引用
  2. 切片长度
  3. cap扩展区域
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7f5CakVx-1648100093923)(E:/youdao/微信截图_20211128215021.png)]
func reSlice() 
	arr := [...]int0,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) 

以上是关于golang简明入门进阶指南02 数组切片map类型的基础使用的主要内容,如果未能解决你的问题,请参考以下文章

golang简明入门进阶指南01golang基础变量函数条件控制

golang简明入门进阶指南01golang基础变量函数条件控制

史上最简明的 Tcpdump 入门指南,看这一篇就够了

阶段1 Go语言基础Day02 数组切片切片原理map字符串处理/字节切片排序

Go数组切片映射的原理--简明解析

有趣的机器学习:最简明入门指南