go语言开发 三种容器类型:数组、切片、map

目录

go语言中的三种容器类型:数组,切片,map

go 与 python的容器类型对比

python

go: 

数组:

数组的定义:(定义数组的格式、二维数组、初始化、任意长度初始化、取值)

数组的遍历

 数组不能进行相加(结果数组并不能相加)

数组的不适应的场景

切片:

切片的定义

切片追加

切片的取值

通过使用切片来定义不限长度的二维数组

切片的修改

数组与切片的区别:

数组与切片在函数调用中的区别:切片被调用时,直接传递引用(数组传切片、切片传切片)go函数传参,传的参都是值

空接口类型,可以存放任何数据类型对象

map

map是什么

使用 map 的语法如下:

key-value的特点

map的定义

遍历map

定义map中value为map 并遍历该map

json与map的转换

map转json

json转map

练习一:验证用户名密码是否正确

练习二:求两个3*3矩阵的和并输出(数据都是int类型)

练习三:使用go编写随机点名系统


go语言中的三种容器类型:数组,切片,map

go 与 python的容器类型对比

python

list -->列表 --》 有顺序的、可变的(元素值、长度可变)

列表存储--》存储为 结构体{元素的地址,其他数据}--》因为存储的是元素的地址(它是连续的),因此列表开辟的内存空间是不连续的

列表切片 --》切出了一个子列表

列表相加 --》[1,2,3]+[2,3,4]--》[1,2,3,2,3,4]

字典 

python的结构体图

go语言开发 三种容器类型:数组、切片、map_第1张图片

go: 

数组 --》有顺序的序列,元素的值可以变,长度不变

数组存储--》会在内存中开辟一块连续的空间,用来保存连续的值(长度不可变)

                -> 数组类型 -> [8]int

                -> 切片 -> 切片类型 -> []int 没有指定长度的数组

go内的数组不能相加

map

go数组内存数据保存空间图

go语言开发 三种容器类型:数组、切片、map_第2张图片

数组:

数组的定义:(定义数组的格式、二维数组、初始化、任意长度初始化、取值)

//数组的定义
func main(){
	//定义数组的格式:
	// var  变量名[长度]类型
	var arr1 [5]int
	arr1[0] = 100
	fmt.Println(arr1)

	//二维数组
	var arr2 [2][3]int
	fmt.Println(arr2)

	//定义数组的同时初始化
	//简短变量声明 :=
	arr3 := [5]int{1,2,3,4,5}
	fmt.Println(arr3)

	//定义时,不确定长度,根据定义数量确认长度
	arr4 := [...]int{1,2,3,4,5,6,7,8}
	fmt.Println(arr4, len(arr4))

	//定义二维数组 使用var定义
	var arr5 = [2][4]int{{1,2},{1,2,3,4}}
	fmt.Println(arr5)

	//取值=> 索引下标从0开始
	fmt.Printf("arr4[2]=%d\n",arr4[2])
	fmt.Printf("arr5[1][0]=%d\n",arr5[1][0])

数组的遍历

	//数组的遍历
	//index -->下标   item --》数组元素
	for index,item := range arr3{
		fmt.Printf("%d,%d\n",index,item)
	}

	for i:=0; i

 数组不能进行相加(结果数组并不能相加)

	//报错:
    // invalid operation: arr1 + arr2 (mismatched types [5]int and [2][3]int)
	// invalid operation: operator + not defined on arr1 (variable of type [5]int)
	//arr1+arr3

数组的不适应的场景

     // 数据长度不固定的时候,不能使用,因为数组的长度是固定的。

切片:

切片的定义

切片是什么  => 动态数组(数组长度可以自己随时定义)
切片追加

	//切片的定义
    方法一:
	var sli []int
	fmt.Printf("切片的数据类型是:%T,值是%v\n", sli, sli)
	var sli1 = []int{1,2,3}
	fmt.Printf("切片的数据类型是:%T,值是%v,长度为%d\n", sli1, sli1, len(sli1))


    方法二:
	//make(type, len, cap)
	//len --> 切片长度(必须给)
	//cap --》 底层数组的容量(可以选择不给,默认值等于len)
	//切片的底层都是数组
	sli2 := make([]int, 3, 5)
	fmt.Printf("sli2的数据类型是:%T,长度为%d,底层数据容量:%d\n", sli2, len(sli2),cap(sli2))

切片追加

    sli2 = append(sli2, 1)
	fmt.Printf("slic2的地址是:%p, 数据是%v, 长度为:%d, 底层数据容量:%d\n",sli2, sli2, len(sli2), cap(sli2))
	sli2 = append(sli2, 2)
	fmt.Printf("slic2的地址是:%p, 数据是%v, 长度为:%d, 底层数据容量:%d\n",sli2, sli2, len(sli2), cap(sli2))
	sli2 = append(sli2, 3,4,5)
	fmt.Printf("slic2的地址是:%p, 数据是%v, 长度为:%d, 底层数据容量:%d\n",sli2, sli2, len(sli2), cap(sli2))

切片的取值

	//切片取值(创建了切片类型)
	//使用 %v 格式化符号时,Go 语言会根据值的类型自动选择相应的格式化方式,如 %d(整数)、%f(浮点数),%v 占位符在 Go 语言中是一种通用的格式化方式,用于根据值的类型输出或格式化对应的结果。
	//%p表示地址
	//%T表示查看数据类型
	fmt.Printf("arr4的地址:%v,%p,%T\n",arr4,&arr4,arr4)
	s1 := arr4[2:5]
	fmt.Printf("arr4[2:5]=%v,%p\n",s1,s1)
	s2 := arr4[:5]
	fmt.Printf("arr4[:5]=%v,%p,%T\n",s2,s2,s2)

通过使用切片来定义不限长度的二维数组

	//你可以通过使用切片来定义不限长度的二维数组
	// 定义一个二维切片
	var arr6 [][]int

	// 添加行
	arr6 = append(arr6, []int{1, 2, 3, 4})
	arr6 = append(arr6, []int{4, 5, 6, 5, 8, 9, 10})
	arr6 = append(arr6, []int{7, 8, 9, 6, 7, 9})

	// 输出二维切片
	fmt.Println(arr6)

切片的修改

切片 => 动态数组 => 引用类型 => 存的是地址

//     => 底层都是数组 => 多个slice共享底层数组

	// 切片的修改(append, copy, 修改、删除)
	// 切片是一个结构体,结构体中有一个指针,存放底层数据的内存地址
	fmt.Printf("sli1的内容:%v, sli2的内容:%v\n", sli1, sli2)
	// 把sli2中内容copy到sli1中
	copy(sli1, sli2)
	fmt.Printf("sli1的内容:%v, sli2的内容:%v\n", sli1, sli2)
	// 修改 下标修改
	sli1[0] = 100
	fmt.Printf("sli1的内容:%v, sli2的内容:%v\n", sli1, sli2)
	// 删除数据
	sli2 = append(sli2[:3],sli2[4:]...)
	fmt.Printf("sli1的内容:%v, sli2的内容:%v\n", sli1, sli2)


	//定义一个数组
	arr7 := [10]int{0,1,2,3,4,5,6,7,8,9}
	//定义了两个切片
	sli71 := arr7[0:6]
	sli72 := arr7[1:7]

	fmt.Printf("arr7的地址是:%p,sli71的数据的地址是:%p,sli72的数据的地址是:%p\n", &arr7, sli71, sli72)
	fmt.Printf("arr7:%v\n sli71:%v\n sli72:%v\n",arr7, sli71, sli72)
	arr7[5] = 104
	fmt.Printf("arr7:%v\n sli71:%v\n sli72:%v\n",arr7, sli71, sli72)
    //数组的值修改,切片的值也会随之修改
    
	// 定义切片的时候会创建一下隐藏数组

练习1(求和、平均数和计数):任意输入10个数,求平均数并输出小于平均数的数,统计小于平均数的个数并输出。

package main

import "fmt"

/*
	练习1(求和、平均数和计数):任意输入10个数,求平均数并输出小于平均数的数,统计小于平均数的个数并输出。
*/

func main()  {
	var arr [10]int

	// 输入10个数据
	for i:=0; i < 10; i++{
		fmt.Printf("请输入第%d个数字:\n", i+1)
		fmt.Scan(&arr[i])
	}
	fmt.Println("arr:", arr)

	//对10个数据进行求和并求平均值
	sum := 0
	for i:=0; i < 10; i++{
		sum += arr[i]
	}
	//防止出现小数的时候,因此使用float64来进行数据类型的转换
	average := float64(sum)/float64(len(arr))
	fmt.Printf("平均数是:%d\n", average)

	// 与平均值比较大小,输出比平均值小的数字
	count := 0
	for _,item := range arr{
		if float64(item) < average{
			fmt.Printf("小于平均数的数是=%d\n", item)
			count++
		}
	}
	fmt.Printf("小于平均数的数一共有%d\n",count)
}

数组与切片的区别:

//  数组的赋值是值的拷贝,是一个全新的数组,不会相互影响(地址不一样)(适合用于修改数据,但不影响本体的案例)
//  而切片的赋值是引用(会一样,地址是一样的)(适合用于查询数据的时候)

// python: a = [1,2,3];b=a; b[0] = 11; a,b => [11,2,3]

	arr7 := [4]int{1,2,3}
	fmt.Printf("arr7的地址是:%p, arr7的数值为:%v\n", &arr7, arr7)
	arr8 := arr7
	fmt.Printf("arr8的地址是:%p, arr8的数值为:%v\n", &arr8, arr8)
	arr8[0] = 10
	fmt.Printf("arr7的值为:%v, arr8的值为:%v\n",arr7, arr8)
	// arr7 => [1,2,3,0]
	// arr8 => [10,2,3,0]

	sli7 := []int{1,2,3,4,5,6,7,8,9}
	sli8 := sli7
	fmt.Printf("sli7的地址是:%p, sli7的数值为:%v\n", sli7, sli7)
	fmt.Printf("sli8的地址是:%p, sli8的数值为:%v\n", sli8, sli8)
	sli8[0] = 10
	fmt.Printf("sli7的数值为:%v, sli8的值为:%v\n",sli7, sli8)

数组与切片在函数调用中的区别:切片被调用时,直接传递引用(数组传切片、切片传切片)
go函数传参,传的参都是值

main函数内:(查看函数内赋值后,对主函数内参数的影响)
	fmt.Println(arr7)
	test(arr7)
	fmt.Println(arr7)

	fmt.Println(sli7)
	test2(sli7)
	fmt.Println(sli7)


函数中:
func test(arr [4]int){
	fmt.Printf("arr的地址是:%p, arr的值是:%v\n", &arr, arr)
	arr[0] = 100
}


// 如果在test2中对arr做了一些修改,sli7一定会发生变化吗?
// 如果arr做的修改,假设底层容器是7,arr的长度10 => 重新生成了一个底层数组
func test2(arr []int){
	fmt.Printf("切片的地址是:%p\n", &arr)
	fmt.Printf("arr的保存地址是:%p, arr的值是:%v\n", arr, arr)
	arr[0] = 100
}

空接口类型,可以存放任何数据类型对象

	// interface{} => nil
	var sli9 = make([]interface{}, 1)
	sli9 = append(sli9, 1)
	sli9 = append(sli9, "a")
	fmt.Println(sli9)

map

map是什么

map是一种数据结构,用于存储键值对的集合。它类似于其他编程语言中的字典、哈希表或关联数组。

python => dict => 字典

它是以hash表的方式存储

使用 map 的语法如下:

var m map[key]value

key-value的特点

// key -> 只可使用可hash对象 如int, float, string, bool, 数组

//        -> 不能引用类型是不可hash对象如切片,interface(接口)

// value -> 能使用任何类型

map的定义

func main(){
	// map的定义:定义不初始化
	// 定义map1, key=>string, value=>string
	var map1 map[string]string
	fmt.Printf("map1的类型是%T,map1的值是%v\n", map1, map1)

	var map2 = make(map[string]string)
	fmt.Printf("map2的类型是%T,map2的值是%v\n", map2, map2)

	// map的定义:定义时初始化
	var map3 = map[string]string{
		"name": "TeacherLiu",
		"age": "34",
		"sex": "female"}

	// map修改值
	map3["name"] = "teacherLiu"
	fmt.Printf("map3的类型是%T,map3的值是%v\n", map3, map3)

	// map增加
	map3["project"] = "Go"
	fmt.Printf("map3的类型是%T,map3的值是%v\n", map3, map3)

	// map取值 => 第一个值是value,第二个值状态(true获取成功,false获取失败)
	fmt.Printf("map[age]的值是:%s",map3["age"])
	//fmt.Printf("map[age1]的值是:%s",map3["age1"])
	value, err := map3["age1"]
	fmt.Printf("value值为:%s, err为:%v\n", value, err)
	value2, err2 := map3["age"]
	fmt.Printf("value值为:%s, err为:%v\n", value2, err2)
	if err2 == true{
		fmt.Printf("获取数据成功\n")
	}

	// map删除值:delete
	delete(map3, "project")
	fmt.Printf("map3的类型是%T,map3的值是%v\n", map3, map3)

遍历map

// 遍历map
	for key := range map3{
		fmt.Printf("key:%s -> %s  ", key, map3[key])
	}
	fmt.Println()
	for key,value2 := range map3{
		fmt.Printf("key:%s -> %s  ", key, value2)
	}

定义map中value为map 并遍历该map

// 定义map中value为map
	var userList = map[string]map[string]string{
		"root":{"password":"123456", "tel":"158xxxxxxxx"},
		"admin":{"password":"123456", "tel":"158xxxxxxxx"},
		"xiaoming":{"password":"123456", "tel":"158xxxxxxxx"}}

	for username,userinfo := range userList{
		fmt.Printf("username:%s", username)
		for key,value := range userinfo{
			fmt.Printf("key:%s -> %s ",key, value)
		}
		fmt.Println()
	}

json与map的转换

    // json是什么? json是一种轻量级的数据交换格式

    // json开发语言的翻译官。  很多语言支持json -> python -> go -> js

    // python 与 go通信 : python -> json <-> go

    // 将数据存储到文件

    // 符合json规范的一个json字符串

map转json

// 如果err1为nil表示,转换成功
	userListJson,err1 := json.Marshal(userList)
	fmt.Printf("转换之后的结果是:%s, %T, err值是:%v\n", userListJson, userListJson, err1)

json转map

	// json转map
	var userData = map[string]map[string]string{}
	err3 := json.Unmarshal(userListJson, &userData)
	fmt.Println(err3)
	fmt.Println(userData)

练习一:验证用户名密码是否正确

验证用户名密码是否正确
  var userList = map[string]map[string]string{
    "root":{"password":"123456", "tel":"158xxxxxxxx"},
    "admin":{"password":"123456", "tel":"158xxxxxxxx"},
    "xiaoming":{"password":"123456", "tel":"158xxxxxxxx"}}
  输入用户名密码,进行验证,验证成功后,输出手机号码

package main

import (
	"fmt"
)

/*
练习4:验证用户名密码是否正确
	var userList = map[string]map[string]string{
		"root":{"password":"123456", "tel":"158xxxxxxxx"},
		"admin":{"password":"123456", "tel":"158xxxxxxxx"},
		"xiaoming":{"password":"123456", "tel":"158xxxxxxxx"}}
	输入用户名密码,进行验证,验证成功后,输出手机号码
*/

//func main()  {
//	var userList = map[string]map[string]string{
//		"root":{"password":"123456", "tel":"158xxxxxxxx"},
//		"admin":{"password":"123456", "tel":"158xxxxxxxx"},
//		"xiaoming":{"password":"123456", "tel":"158xxxxxxxx"}}
//
//	var user string
//	var passwd string
//	var flag int
//	count := 0
//
//	for true{
//		// 无限循环的代码块
//		fmt.Printf("请输入用户名:")
//		fmt.Scan(&user)
//		//fmt.Println(user)
//		for username,userinfo := range userList{
//			if user != username {
//				count ++
//			} else {
//				fmt.Printf("请输入密码:")
//				fmt.Scan(&passwd)
//				if passwd == userinfo["password"] {
//					fmt.Printf("验证成功,手机号为:%s",userinfo["tel"])
//					flag = 1
//					break
//				} else {
//					fmt.Printf("密码错误")
//					break
//				}
//			}
//			if count == 3 {
//				fmt.Printf("用户名输入错误,请重新输入")
//			}
//		}
//		fmt.Println()
//		if flag == 1{
//			break
//		}
//	}
//}

func main()  {
	var user string
	var flag bool
	var tel string

	for true {
		// 无限循环的代码块
		fmt.Printf("请输入用户名:")
		fmt.Scan(&user)
		tel,flag = auto(user)
		if flag{
			fmt.Printf("验证成功,手机号为:%s\n",tel)
			break
		}else if tel == "1" {
			fmt.Printf("密码输入错误\n")
		} else{
			fmt.Printf("用户名输入错误,请重新输入\n")
		}
	}
}

func auto(user string) (string,bool)  {
	var userList = map[string]map[string]string{
		"root":{"password":"123456", "tel":"158xxxxxxxx"},
		"admin":{"password":"123456", "tel":"158xxxxxxxx"},
		"xiaoming":{"password":"123456", "tel":"158xxxxxxxx"}}

	var passwd string

	for username,userinfo := range userList{
		if user == username {
			fmt.Printf("请输入密码:")
			fmt.Scan(&passwd)
			if passwd == userinfo["password"] {
				return userinfo["tel"],true
			} else {
				return "1",false
			}
		}
	}
	return "",false
}

练习二:求两个3*3矩阵的和并输出(数据都是int类型)

求两个3*3矩阵的和并输出(数据都是int类型)
       解析:矩阵的和计算规则是对应元素相加:
       c[i][j] = a[i][j] + b[i][j]

package main

import "fmt"

/*
练习2:求两个3*3矩阵的和并输出(数据都是int类型)
	解析:矩阵的和计算规则是对应元素相加:
	c[i][j] = a[i][j] + b[i][j]
*/

func main()  {

	var arr1 = [3][3]int{{1,2,3},{1,2,3},{1,2,3}}
	var arr2 = [3][3]int{{3,2,1},{3,2,1},{3,2,1}}
	var arr3 [3][3]int

	for i:=0; i<3; i++{
		for j:=0; j<3; j++{
			arr3[i][j] = arr2[i][j] + arr1[i][j]
		}
	}
	fmt.Println(arr3)
}

练习三:使用go编写随机点名系统

使用go编写随机点名系统
切片类型存放全班同学的名字:["史伟名","易鸽玲"]
按任意键,不限次数随机抽取切片中的某一个同学名字回答问题
     抽取到的同学就从切片中删除
按q退出,或者切片里面所有的同学都已近被抽到

package main

import (
	"fmt"
	"math/rand"
	"time"
)

/*使用go编写随机点名系统
切片类型存放全班同学的名字:["史伟名","易鸽玲"]
按任意键,不限次数随机抽取切片中的某一个同学名字回答问题
		 抽取到的同学就从切片中删除
按q退出,或者切片里面所有的同学都已近被抽到*/

func main()  {
	var name = []string{"史伟名","易鸽玲","李泉","潘林枫","夏彪"}

	for  {
		fmt.Println("按下任意字符键(按q退出):")
		var input string
		fmt.Scanln(&input)
		if input == "q" {
			break
		}else if len(name) == 1{
			fmt.Println("回答问题的同学是:", name[0])
			fmt.Printf("切片里面所有的同学都已经被抽到")
			break
		}
		// 生成随机索引
		randomIndex := random(len(name))

		// 随机选择一个同学名字回答问题
		answername := name[randomIndex]
		fmt.Println("回答问题的同学是:", answername)

		//将抽取到的同学从切片中删除
		copy(name[randomIndex:], name[randomIndex+1:])
		name = name[:len(name)-1]

	}
}

//生成随机数
func random(num int) int {
	/*
	test1 是函数的名称,根据实际需求可以自定义一个有意义的函数名。
	(num int) 是函数的参数列表,指定了函数接收的参数。在这个例子中,函数接受一个名为 num 的整数类型参数。
	int 是函数的返回类型,指定了函数返回的结果类型。在这个例子中,函数返回一个整数。
	*/
	//为随机数生成器设置种子的操作。
	rand.Seed(time.Now().UnixNano())

	// Intn returns, as an int, a non-negative pseudo-random number in the half-open interval [0,n)
	// from the default Source.
	// It panics if n <= 0.
	// 说明Intn()中的num 必须大于0 否则的话会出现panics
	return rand.Intn(num)
}

你可能感兴趣的:(golang,开发语言,后端)