• Go基本数据类型


    在这里插入图片描述

    基本数据类型

    package main
    
    import (
    	"errors"
    	"fmt"
    	"unsafe"
    )
    
    func defaultValue() {
    	var a int
    	var b byte
    	var c bool
    	var d string
    	var e rune
    	var f []int
    	var g struct{}
    	var h float64
    
    	var com complex64
    	com = complex(3, 5)
    	var com2 complex128
    	com2 = complex(3, 5)
    	fmt.Printf("defaultValue %d\n", a)
    	fmt.Printf("defaultValue %d\n", b)
    	fmt.Printf("defaultValue %t\n", c)
    	fmt.Printf("defaultValue [%s]\n", d)
    	fmt.Printf("defaultValue %c\n", e)
    	fmt.Printf("defaultValue %d\n", f)
    	fmt.Printf("defaultValue %d\n", g)
    	fmt.Printf("defaultValue %f\n", h)
    
    	fmt.Print("字符串长度")
    	fmt.Println(unsafe.Sizeof(d))
    
    	fmt.Println(com)
    	//实部和虚部是浮点数
    	//real实数内置函数返回复数 c 的实部,返回值将是与 c 类型对应的浮点类型。
    	//imag 内置函数返回复数的虚部数字 c.返回值将是浮点类型对应c 的类型。
    	fmt.Printf("%T %T\n", real(com), imag(com))
    	fmt.Printf("%T %T\n", real(com2), imag(com2))
    
    }
    
    func main() {
    	//defaultValue()
    	defaultV()
    
    	var bb = 100
    	fmt.Printf("%T\n", bb)
    	var bbb byte = 100 //byte等价于uint8
    	fmt.Printf("%T\n", bbb)
    	var cc rune = '中' //rune等价于int32
    	fmt.Printf("%T\n", cc)
    	var dd rune = '😊' //unicode
    	fmt.Printf("%T\n", dd)
    	fmt.Println('😀') //128512
    	errType()
    	structType()
    }
    
    func defaultV() {
    
    	var a int
    	var pointer unsafe.Pointer = unsafe.Pointer(&a) //指向a
    	var ppt uintptr = uintptr(pointer)              //无符号指针
    	var pit *int = &a                               //指向a
    	fmt.Printf("pointer %p ,ppt %d %x,pit %p\n", pointer, ppt, ppt, pit)
    
    }
    
    func errType() {
    	var err error
    	err = errors.New("这就是一个错误的描述")
    
    	fmt.Printf(" %v\n", err) // 这就是一个错误的描述
    
    }
    func structType() {
    	type Person struct {
    		name string
    		age  int
    	}
     
    	var per = Person{"张三", 18}
    	fmt.Printf("%v\n",per)//打印值
    	fmt.Printf("%+v\n",per)//带字段打印值
    	fmt.Printf("%#v\n",per)//带字段,而且还会打印出带包的方法
    }
    }
    
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    在这里插入图片描述
    我们在源码里会看到 关于类型的定义—>>有一个专门的go文件:用于定义我们的数据类型;
    在这里插入图片描述

    自定义数据类型:

    比如:

    type signal uint8//定义一个信号量
    type mmap map[string]string //定义一个map
    type add func(a,b int) int//定义函数
    type man struct { //定义结构体
    	name string
    	age int
    }
    type comp complex64
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    自定义类型的用法

    每一种自定义类类型都可以有自己的方法,当我们给自定义类型赋值时(有的需要初始化),可以调用相应的方法;
    如下代码可以参考:

    type signal uint8           //定义一个信号量
    type mmap map[string]string //定义一个map
    type add func(a, b int) int //定义函数
    type man struct {           //定义结构体
    	name string
    	age  int
    }
    type comp complex64
    
    func (m mmap) Eat() {
    
    	fmt.Printf("中国首都 %s\n", m["中国"])
    	//m.Eat() //这是回调
    }
    func (app add)test(a ,b int)  {
    	result:=a+b
    	fmt.Printf("%d\n",app(result,10))
    }
    func (you man) SayHi(say string) {
    	fmt.Printf("my name is %s 年龄是 %d", you.name, you.age)
    
    }
    func main() {
    	var u man
    	u = man{name: "小明", age: 19}
    	u.SayHi("大家好")
    
    	var demo mmap//如果不初始化map,就会得到一个nil map,这种map不会用来存放信息
    	demo=make(map[string]string)
    	demo["中国"]="北京"
    	demo["hello"] = "world"
    	demo.Eat()
    
    
    
    	var cse add
    	cse= func(a, b int) int {//就是重写函数
    		return a+b
    	}
    	cse.test(10,20)
    	
    	defaultV()
    
    • 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
    • 38
    • 39
    • 40
    • 41
    • 42

    数组

    	//声明数组
    	var arr0 []int //如果不在这里声明长度,下面又直接指定数组中某个元素的值,会报错 panic: runtime error: index out of range [0] with length 0
    	arr0[0]=100  //这里会报错
    	arr0=[]int{2,3,4}  //其实跟java一样的声明数组的方式  
    	fmt.Println(arr0)
    
    	var arr = [5]int{}
    	arr[0] = 2
    	var arr1 = [5]int{2, 3}
    
    	fmt.Printf("%d\n", arr1[1])
    	var arr2 = [5]int{2: 12, 4: 233}//可以为指定位置的元素附上值
    	fmt.Println(arr2)
    	var arr3 = []struct { //结构体数组
    		name string
    		age  int
    	}{{"小明", 12}, {"小红", 13}}
    	fmt.Println(arr3)
    
    //有下面的写法,可以不写数组的长度,通过反推得出数组长度
    	var arr2 = []int{2: 12, 4: 233}//像这种,最好写上数组长度
    	fmt.Println(arr2)
    
    	var arr3 = [...]struct {//也可以通过...的方式写上数组的长度----反推出数组的长度
    		name string
    		age  int
    	}{{"小明", 12}, {"小红", 13}}
    	fmt.Println(arr3)
    
    
    
    • 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

    二维数组:

    	//二维数组
    	var array1=[4][6]int{{1,2,3,4,5,6},{8,9}}
    	fmt.Println(array1)
    
    	//二维数组只有第一维可以推断
    	var array2=[][5]int{{1,2,3,4},{5,6,7}}
    	fmt.Println(array2)
    	fmt.Println(array2[1][3])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    在这里插入图片描述

    访问数组的方式

    通过下标进行访问

    fmt.Println(arr2[3])
    fmt.Println(array2[1][3])
    
    • 1
    • 2

    数组的遍历

    一维数组:

    	var stu [10]int=[10]int{1,2,3,4,5,6,7,8,9,10}
    	for i := 0; i < len(stu); i++ {
    		fmt.Printf("下标stu[ %d] 值为%d\n",i,stu[i])
    	}
    
    	for i, ele:=range stu {
    
    		fmt.Printf("下标stu[ %d] 值为%d 那stu[%d]\n",i,ele,stu[i])
    
    	}
    	for _, ele:=range stu {
    		fmt.Printf("%d\n", ele)
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    二维数组

    这个其实跟java的代码写法类似:

    fmt.Println("----------------------")
    	var fast = [4][5]int{{1, 2, 3, 4, 5}, {5, 4, 3, 2, 1}, {6, 7, 8, 9}, {9, 8, 7, 6}}
    	//遍历二维数组
    	for i := 0; i < len(fast[i])-1; i++ {
    		for j := 0; j < len(fast[j]); j++ {
    			fmt.Println(fast[i][j])
    		}
    
    	}
    	fmt.Println("--------------------------------")
    	for row, arr := range fast {
    		for col, ele := range arr {
    			fmt.Printf("a[%d][%d]=%d\n", row, col, ele)
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    关于数组的几个方法:

    由于数组在初始化之后长度不会变了,不需要给他预留空间,所以cap(stu)=len(stu)

    	var stu [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    	fmt.Println(cap(stu))//容量 10
    	fmt.Println(len(stu))//长度10
    
    • 1
    • 2
    • 3
    cap()方法的解释:
    	//数组:v中的元素个数(与len(v)相同)。
    
    	//指向数组的指针:*v中的元素数量(与len(v)相同)。
    
    	//切片:切片时所能达到的最大长度;
    
    	//如果v是空的,cap(v)是零。
    
    	// channel:通道缓冲区容量,以元素为单位;
    
    	//如果v是空的,cap(v)是零。
    	
    len()方法的解释:
    / array: v中元素的个数。
    
    //指向数组的指针:*v中的元素数量(即使v为nil)。
    
    //切片或映射:v中的元素数量;如果v为nil, len(v)为零。
    
    //字符串:v。
    
    // channel:通道缓冲区中排队(未读)的元素数量;
    
    //如果v为空,len(v)为零。
    
    • 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

    数组的长度和类型都是数组类型的一部分,函数传递数组类型时这两部分都必须吻合

    即声明一个数组 要求必须指定长度 即[8]int

    为什么这么说呢?
    我们来看一个代码案例:

    func avgMethod(haha[10]int) float64 {
    	var sum int
    	for i := 0; i < len(haha); i++ {
    		sum+=haha[i]
    	}
    	return float64(sum / len(haha))
    }
    func main() {
    	//var tea []int
    	var stu [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    	fmt.Printf("%f\n",avgMethod(stu))
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述
    现在如果我们在方法avgMethod方法中修改数组的值,其实是不影响原数组stu的,因为传入参数时是值的拷贝,而不是数组自身被传进去了,这跟java中是一样的,值传递;

    在这里插入图片描述

    切片

    Go 语言切片是对数组的抽象。

    Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。在这里插入图片描述
    切片跟数组很像,但是切片不用像数组哪一样要指定长度;

    数组 var arr=[10]int{}
    切片 var sli []int=[]int{}

    当我们声明数组时,如果没有给数组中元素赋值,则为默认的值, 如果是切片,则并不会给他赋值;

    package main
    
    import (
    	"fmt"
    	"unsafe"
    )
    
    // 切片的地址跟数组首元素的地址是两码事
    type slice struct { //切片由三部分组成
    	array unsafe.Pointer
    	len   int
    	cap   int
    }
    
    func main() {
    	var s []int        //声明一个切片 len=cap=0
    	
    	s = []int{1, 2, 3} //切片初始化方式1(数组要指定长度的,所以这是切片)
    	fmt.Println(s)
    	var ss[]byte
    	ss = make([]byte, 3) //初始化 ,len=cap=3
    	//可以不屑写cap,不写则默认len=cap--即下面的方式
    	ss=make([]byte, 3,3)
    	fmt.Println(ss)
    
    	sss:=make([]rune,3,5)//初始化 ,len=3,cap=5
    	fmt.Printf("%p\n",&sss)
     
    
    }
    
    
    • 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

    二维切片:

    	//二维数组
    	arr:=[3][]int{{1},{2,3,4}}
    	//二维切片
    	slice2d := [][]int{{1}, {2, 3, 4}}
    	fmt.Println(arr)
    	fmt.Println(slice2d)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    结果可以看看到,二维切片与二维数组的区别:
    二维切片各行的len可以不相等,但是二维数组各行的len要相等
    cap 与len

    	sss := make([]int, 3, 5) //初始化 ,len=3,cap=5
    	fmt.Println(sss)
    	fmt.Println(len(sss))
    	fmt.Println(cap(sss))
    
    • 1
    • 2
    • 3
    • 4

    切片的扩容机制

    数组一旦声明,他的容量就被限制了,而切片就好像java中的集合---->>

    随着元素的个数增加,他的len也在增加,他的cap也会发生变化

    	//切片的扩容
    	var numbers []int
    
    	for i := 0; i < 10; i++ {
    		numbers = append(numbers, i)
    		fmt.Printf("len: %d  cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)
    	}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    切片现在时这个状态:
    在这里插入图片描述
    在这里插入图片描述
    当cap大于1024时他的扩容

    	//切片的扩容
    	var numbers []int
    
    	for i := 0; i < 1280; i++ {
    		numbers = append(numbers, i)
    		fmt.Printf("len: %d  cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)
    	}
    	//向切片中追加元素
    	numbers=append(numbers,11,12,13,14,15,16,17)
    	numbers=append(numbers,18)
    	fmt.Printf("len: %d  cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    为了更直观的查看扩容机制—请看下面的代码:

    func KuoRong() {
    	s := make([]int, 0, 10)
    	//扩容前的切片中数组的长度与切片容量
    
    	preCap := cap(s)
    	for i := 0; i < 1185; i++ {
    		s = append(s, 0)
    		//追加元素后的切片中数组的长度与切片容量
    
    		currCap := cap(s)
    		if currCap > preCap {
    			fmt.Printf("Cap %d 扩容到了 %d\n", preCap, currCap)
                //以前的,现在的
    			preCap = currCap
    		}
    
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    append方法的描述:

    append内置函数在片的末尾追加元素。如果它有足够的容量,目的地被切片以容纳新元素。如果没有,将分配一个新的底层数组
    Append返回更新后的片。因此,有必要存储append的结果,通常在保存切片本身的变量中: slice = append(slice, elem1, elem2) slice = append(slice, anotherSlice…)
    作为特殊情况,它是合法的附加字符串到字节片,像这样: slice = append([]byte("hello "), “world”…)

    小结:
    切片相对于数组,他的特点是可以追加元素,可以自动扩容,追加的元素放到预留的内存空间内,同时len增加1
    如果预留空间用完,则会重新申请一块更大的内存空间---->>
    cap变为之前的2倍或者1.**倍 ,之后把原内存空空间的数据拷贝过来,在新内存空间上执行append操作具体的倍数还不一致,大体知道这个就可以了

    子切片

    func SonSlice() {
    	//定义一个切片
    	arr := make([]int, 5, 8)
    	for i := 0; i < len(arr); i++ {
    		arr[i]=i
    	}
    
    	fmt.Println(arr)
    	//截取子切片
    	sub:=arr[0:2]
    	fmt.Println(sub)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    当我们修改子切片中的内容时:
    母切片中的内容也会发生改变

    sub[0]=100
    	sub[1]=102
    	fmt.Println(arr)
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    子切片与母切片共享内存空间
    当我们打印母切片与子切片的地址时:

    fmt.Printf("%p\n",arr)
    	fmt.Printf("%p\n",sub)
    
    • 1
    • 2

    两个的地址是一样的;

    这是因为子切片而引用了切片中数组的首元素,所以地址是一样的

    在这里插入图片描述

    在这里插入图片描述

    如果切片不是引用数组首元素,像这样—>>

    //定义一个切片
    	arr := make([]int, 5, 8)
    	for i := 0; i < len(arr); i++ {
    		arr[i]=i
    	}
    	fmt.Printf("%p\n",arr)
    	fmt.Println(arr)
    	//截取子切片
    	sub:=arr[2:4]
    	fmt.Println(sub)
    	sub[0]=100
    	sub[1]=102
    	fmt.Println(arr)
    	fmt.Printf("%p\n",arr)
    	fmt.Printf("%p\n",sub)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    当我们的母切片容量满了的时候:

    func SonSlice() {
    	//定义一个切片
    	arr := make([]int, 5, 8)
    	for i := 0; i < len(arr); i++ {
    		arr[i]=i
    	}
    fmt.Printf("%p\n",&arr)//这里也是最新的地址
    	fmt.Println(arr)
    	//截取子切片
    	sub:=arr[0:2]
    	fmt.Println(sub)
    	//母切片arr满了时,再添加一个元素
    	arr=append(arr,10)
    	arr=append(arr,11)
    	arr=append(arr,12)
    	//查看地址
    	fmt.Printf("%p\n",&arr)
    	fmt.Printf("%p\n",&sub)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述
    此时我们修改子切片的内容

    	sub[0]=100
    	sub[1]=102
    	//打印母切片的内容
    	fmt.Println(arr)
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    发现依然被修改了,这说明母切片与子切片的联系并没有被切断(这是因为此时还没有扩容)

    如果扩容了
    贴一段完整的代码:

    func SonSlice() {
    	//定义一个切片
    	arr := make([]int, 5, 8)
    	for i := 0; i < len(arr); i++ {
    		arr[i]=i
    	}
    	fmt.Printf("%p\n",arr)
    	fmt.Println(arr)
    	//截取子切片
    	sub:=arr[2:4]
    	fmt.Println(sub)
    	sub[0]=100
    	sub[1]=102
    	fmt.Println(arr)
    	fmt.Printf("%p\n",arr)
    	fmt.Printf("%p\n",sub)
    
    	//母切片arr满了时,再添加四个元素
    	arr=append(arr,10)
    	arr=append(arr,11)
    	arr=append(arr,12)
    	//内存分离
    	arr=append(arr,13)
    	//查看地址
    	fmt.Printf("%p\n",&arr)
    	fmt.Printf("%p\n",&sub)
    
    	//此时修改母切片中的值
    	arr[2]=9999
    	arr[3]=9999999
    	fmt.Println(sub)//100,102
    
    	//那如果是求改子切片的数据会不会影像母切片呢
    
    	sub[0]=100
    	sub[1]=102
    	fmt.Println(arr)
    }
    
    • 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
    • 38

    在这里插入图片描述

    当母切片扩容时,原母切片会与当时的子切片进行内存的分离,即此时修改母切片/子切片都会互不影响;

    即切片是对数组的一种引用,但又不是数组,只是指针都指向同一块内存空间;

    所以,go语言中函数传参传的都是值,即传切片会把切片中的字段(指针,长度,容量)都拷贝一份传进来;
    由于传的是底层数组的指针,所以是可以直接修改底层数组的元素的;

    我们来看一段代码案例:

    func main(){
    var arr []int = []int{1, 2, 3}
    	test(arr)
    	fmt.Println(arr)
    
    	var arr2 = [3]int{
    		1, 2, 3,
    	}
    	test2(arr2)
    	fmt.Println(arr2)
    
    // 这个传的是切片
    func test(arr []int) {
    
    	arr[1] = 100
    	fmt.Printf("%s %d\n", "在这个方法中", arr[1])
    }
    // 这个传的是数组
    func test2(arr [3]int) {
    
    	arr[1] = 100
    	fmt.Printf("%s %d\n", "在这个方法中", arr[1])`在这里插入代码片`
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    如果是切片,我们发现原切片中的值已经被修改了,如果是数组,则原数组中的值没有被修改
    在这里插入图片描述

    map

    go中的map 底层实现是hash table 根据key查找valuede 时间复杂度是O(1)

    key1 根据hash算法算出一个hash值,然后对槽位总数取模,得到的值,就将这个值插入到这个位置;

    当hash冲突太多时,需要扩容来解决,即增加槽位数,给每个key重新分配槽位数;

    Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

    Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

    func MapTest() {
    	//声明一个map
    	var map1 map[string]string
    	//需要实例化
    	map1=make(map[string]string,8)
    	map1["姓名"]="小花"
    	fmt.Println(map1)
    	map2:= make(map[string]string,8)
    	map2["1"] = "小明"
    	map2["2"] = "小明"
    	map2["3"] = "小明"
    	map2["4"] = "小明"
    	map2["5"] = "小明"
    	map2["6"] = "小明"
    	map2["7"] = "小明"
    	map2["8"] = "小明"
    
    	for name:=range map2{
    		fmt.Printf("%s  %s\n" ,name,map2[name])
    	}
    
    
    	//删除元素
    	delete(map2,"8")//删除key为1的元素
    	for name:=range map2{
    		fmt.Printf("%s  %s\n" ,name,map2[name])
    	}
    
    }
    
    • 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

    当key重复时—>>

    func MapTest() {
    
    	//声明一个map
    	var map1 map[string]string
    	//需要实例化
    	map1 = make(map[string]string, 8)
    	map1["姓名"] = "小花"
    	fmt.Println(map1)
    	map2 := make(map[string]string, 8)
    	map2["1"] = "小明"
    	map2["2"] = "小明"
    	map2["3"] = "小明"
    	map2["4"] = "小明"
    	map2["5"] = "小明"
    	map2["6"] = "小明"
    	map2["8"] = "小明1"
    	map2["8"] = "小明2"
    	//有重复的key,后来的替换掉之前的
    	fmt.Println("有重复的key", map2)
    	//这里证明是无序的
    	for name := range map2 {
    		fmt.Printf("%s  %s\n", name, map2[name])
    	}
    	fmt.Println(len(map2))
    	//删除元素
    	delete(map2, "8") //删除key为8的元素
    	fmt.Println("在这里", map2)
    
    	for name := range map2 {
    		fmt.Printf("%s  %s\n", name, map2[name])
    	}
    
    }
    
    • 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

    在这里插入图片描述
    查找map中的元素:

    第一种方式—>>fmt.Println("查找key为 10",map2["10"])
    直接输出该key对应的值,但是有一点,是要明确map中的数据是非空或者有其他限制的,不然无法确定查找的map[key],如果是默认值呢?

    第二种方式---->>

    //根据key找value
    	if value ,exists:=map2["100"];exists{
    		fmt.Println(value)
    	}else{
    		fmt.Println("不存在")
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    leetcode94 -- 二叉树的中序遍历
    代码坏味道
    06 - ip route和route -n的区别
    @HttpMessageConverter注解的基本介绍
    香港服务器减少延迟的几种方法
    centos7下mongodb安装及开启副本
    搜索与图论-树与图的深度优先遍历
    BI系统打包Docker镜像及部署的技术难度和实现
    15.【opencv写入录制视频】
    前端程序员兼职副业平台推荐
  • 原文地址:https://blog.csdn.net/weixin_54061333/article/details/126236558