目录
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编写随机点名系统
list -->列表 --》 有顺序的、可变的(元素值、长度可变)
列表存储--》存储为 结构体{元素的地址,其他数据}--》因为存储的是元素的地址(它是连续的),因此列表开辟的内存空间是不连续的
列表切片 --》切出了一个子列表
列表相加 --》[1,2,3]+[2,3,4]--》[1,2,3,2,3,4]
字典
python的结构体图
数组 --》有顺序的序列,元素的值可以变,长度不变
数组存储--》会在内存中开辟一块连续的空间,用来保存连续的值(长度不可变)
-> 数组类型 -> [8]int
-> 切片 -> 切片类型 -> []int 没有指定长度的数组
go内的数组不能相加
map
go数组内存数据保存空间图
//数组的定义
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)
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是一种数据结构,用于存储键值对的集合。它类似于其他编程语言中的字典、哈希表或关联数组。
python => dict => 字典
它是以hash表的方式存储
map
的语法如下:var m map[key]value
// key -> 只可使用可hash对象 如int, float, string, bool, 数组
// -> 不能引用类型是不可hash对象如切片,interface(接口)
// value -> 能使用任何类型
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
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
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是什么? json是一种轻量级的数据交换格式
// json开发语言的翻译官。 很多语言支持json -> python -> go -> js
// python 与 go通信 : python -> json <-> go
// 将数据存储到文件
// 符合json规范的一个json字符串
// 如果err1为nil表示,转换成功
userListJson,err1 := json.Marshal(userList)
fmt.Printf("转换之后的结果是:%s, %T, err值是:%v\n", userListJson, userListJson, err1)
// 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类型)
解析:矩阵的和计算规则是对应元素相加:
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编写随机点名系统
切片类型存放全班同学的名字:["史伟名","易鸽玲"]
按任意键,不限次数随机抽取切片中的某一个同学名字回答问题
抽取到的同学就从切片中删除
按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)
}