常量运行期间,不可以改变的值
const PI float64 = 3.14
字面常量
所谓字面常量,是值程序中硬编码的常量
123 //整型类型常量
156.78 //浮点类型的常量
true //布尔类型的常量
“abc”//字符串类型的常量
//const PI float64 = 3.14
const PI = 3.14 //
//PI = 3.15 //cannot assign to PI 不允许修改常量的值
//fmt.Printf("%p", &PI)//: cannot take address of PI 不允许打印常量的地址
fmt.Printf("%f\n", PI)
算术运算符
var num1 int = 20
var num2 int = 10
//num1+num2 = 30
//num1-num2 = 10
//num1*num2 = 200
//num1/num2 = 2
//num1%num2 = 0
fmt.Println("num1+num2 = ", num1+num2)
fmt.Println("num1-num2 = ", num1-num2)
fmt.Println("num1*num2 = ", num1*num2)
fmt.Println("num1/num2 = ", num1/num2)
fmt.Println("num1%num2 = ", num1%num2)
除法运算和取余预算除数不能为0
自增自减运算符
var num int = 10
num++
fmt.Println(num)
赋值运算符
var num int = 10
num += 10
fmt.Println(num)
num -= 10
fmt.Println(num)
num %= 2 + 3 //先算+ 后算%=
fmt.Println(num)
算术>赋值
关系运算符
var num1 int = 10
var num2 int = 20
fmt.Println("num1 == num2 ", num1 == num2) //false
fmt.Println("num1 != num2 ", num1 != num2) //true
fmt.Println("num1 >=num2 ", num1 > num2) //false
fmt.Println("num1 < num2 ", num1 < num2) //true
fmt.Println("num1 >= num2 ", num1 >= num2) //false
fmt.Println("num1 <= num2 ", num1 <= num2) //true
关系运算符只能是true或者false
sum := num1+20 > num2 //先算算术 算术>关系>赋值
fmt.Println("sum = ", sum)
逻辑运算符
var num1 int = 10
var num2 int = 20
isResult := num1 > num2
fmt.Println("isResult = ", isResult)
fmt.Println("isResult = ", !isResult)
// 逻辑运算符不能跟整型 逻辑非后面的变量是布尔布尔类型 。逻辑非的运算符优先级高于关系运算符
fmt.Println(!(num1 > num2)) //invalid operation: operator ! not defined on num1 括号的优先级要高于逻辑非
//逻辑与
fmt.Println(num1 > num2 && num1 == 10) //false 逻辑与运算符优先级低于关系运算符
//逻辑或
fmt.Println(num1 > num2 || num1 == 10) //true 逻辑或运算符优先低于关系运算符
fmt.Println(num1 > num2 || num1 > num2 && num1 != 0) //false 逻辑与的优先级高于逻辑或
fmt.Println(num1 < num2 || num1 > num2 && num1 != 0) //true 逻辑与的优先级高于逻辑或
Switch中fallthrough,如果写了这个就往下执行fallthrough
// TestSum 不定参数
// 如果只写一个变量,该变量中存储的是集合的编号
// _:匿名变量。匿名变量不会保存具体的数据
func TestSum(args ...int) {
for i := 0; i < len(args); i++ { //len 可以获取参数的存储的数据的个数
fmt.Println(args[i])
}
//集合
for i, v := range args { //
fmt.Println("i = ", i) //i集合的编号。
fmt.Println("v = ", v) //v存储的是具体的值
}
}
/*
func AddResult(num1 int,num2 int) int { // 表示指定函数返回的数据的类型。
var sum int
sum = num1+num2
return sum //将变量sum中存储的值返回。
}
*/
// 表明:最终会返回整型变量sum中的值。
// 在函数体中没有必要在重新创建sum变量。
/*
func AddResult(num1 int,num2 int) (sum int) {
// var sum int
sum = num1+num2
return sum //将变量sum中存储的值返回。
}
*/
func AddResult(num1 int,num2 int) (sum int) {
// var sum int
sum = num1+num2
return //如果已经指定了返回的变量的名称,那么return后面可以不用在加上变量的名称。
}
func GetResult()(num1 int,num2 int){
//var num1 int = 10
// var num2 int = 20
num1=10
num2=20
//return num1,num2 //表明返回两个变量的值。
return
}
func GetResult()(int,int){
//var num1 int = 10
// var num2 int = 20
num1=10
num2=20
//return num1,num2 //表明返回两个变量的值。
return
}
数组
/*
var Numbers[5] int = [5]int{1,2,3,4,5} // 下标是从0开始计算的。
fmt.Println(Numbers[3])
*/
// 部分赋值
/*
Numbers := [5]int{1,2}
fmt.Println(Numbers[4])
*/
// 指定某个元素初始化
/*
Numbers :=[5]int{2:5,3:6}
fmt.Println(Numbers[3])
*/
//通过初始化确定数组长度
/*
Numbers :=[...]int{7,8,5}
//fmt.Println(len(Numbers))
fmt.Println(Numbers[0])
*/
var Numbers [5] int
/*
Numbers[0]=1
Numbers[1]=2
fmt.Println(Numbers[3])
*/
for i := 0; i < len(Numbers); i++ {
Numbers[i] = i + 1
}
fmt.Println(Numbers[0])
数组比较
package main
import "fmt"
func main() {
// 完成两个数组中元素的比较,判断其相同下标对应的元素是否完全一致。
// 1: 判断两个数组的长度是否一致。
// 2: 判断值是否一致。
var num1 [5]int = [5]int{1, 2, 3, 4, 5}
var num2 [5]int = [5]int{3, 2, 3, 4, 5}
fmt.Println(num1!=num2)
/*
b := compareValue(num1, num2)
if b {
fmt.Println("数组一致")
} else {
fmt.Println("数组不一致")
}
*/
}
func compareValue(n1 [5]int, n2 [5]int) bool {
var b bool = true
// 1: 判断两个数组的长度是否一致。
if len(n1) == len(n2) {
// 2: 判断值是否一致。
for i := 0; i < len(n1); i++ {
if n1[i] == n2[i] {
continue
} else {
b = false
break
}
}
} else {
b = false
}
return b
}
二维数组
package main
import "fmt"
func main() {
// var arr [2][3]int = [2][3]int{{1, 2, 3}, {5, 6, 7}} // 全部初始化
// 部分初始化
// var arr [2][3]int = [2][3]int{{1,2},{6}}
// 指定元素初始化
// var arr [2][3]int = [2][3]int{0:{1:6}}
// 通过初始化确定二维数组行数
// arr := [...][3]int{{1, 2, 3}, {5, 6}} // 行的下标可以用"..."来代替,但是列的下标不能用"..."来代替。
// fmt.Println(arr)
// 通过循环遍历的方式输出打印二维数组中的值。
var arr [2][3]int = [2][3]int{{1, 2, 3}, {5, 6, 7}}
// fmt.Println(len(arr)) // 输出的是有几行。
//fmt.Println(len(arr[0])) // 输出有几列。
// fmt.Println(arr[0])
/*
for i := 0; i < len(arr); i++ { // 遍历的行
for j := 0; j < len(arr[0]); j++ { // 遍历的是列。
fmt.Println(arr[i][j])
}
}
*/
for _, v := range arr {
//fmt.Println("i", i)
//fmt.Println("v", v)
for j, data := range v {
fmt.Println("j:",j)
fmt.Println("data:",data)
}
}
/*
arr[0][1]=123
arr[1][1]=456
fmt.Println(arr[0][1])
*/
}
切片
切片与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大,
所以可以将切片理解成“动态数组”,但是,它不是数组。
3. 使用make( )函数创建
长度是已经初始化的空间。容量是已经开辟的空间,包括已经初始化的空间和空闲的空间。
//var s []int
//s := []int{}
s := make([]int, 3, 5) //长度已经初始化的空间为3,容量是已经开辟的空间5,包括已经初始化的空间和空闲的空间 长度不能大于容量
fmt.Println(s)
fmt.Println(len(s))
fmt.Println(cap(s))
1 make(切片类型, 长度, 容量)
2.长度是已经初始化的空间。容量是已经开辟的空间,包括已经初始化的空间和空闲的空间。
3.在使用make( )函数定义切片时,一定要注意,切片长度要小于容量
4 len( )函数返回长度,cap( )返回容量
5 make( )函数中的容量参数是可以省略掉的,这时容量与长度是相等的。
切片初始化
//var s []int
//s = append(s, 1, 2, 3, 4, 5)
//fmt.Println(s)
//s := []int{8, 9, 7, 10, 12}
//s = append(s, 99, 100)
//s[0] = 78
//fmt.Println(s)
s := make([]int, 3, 10)
s[0] = 10
s[1] = 20
s[2] = 30
//s[4] = 80下标越界
fmt.Println(s)
s := make([]int, 3, 10)
for i := 0; i < len(s); i++ {
s[i] = i + 1
}
s = append(s, 80)
fmt.Println(s)
切片截取
s := []int{3, 5, 6, 7, 8, 9}
//第一个值:截取的起始位置
//第二个值:截取的终止位置(不包含该值的)
//第三个值:用来计算容量,容量值的是切片中最多能够容纳多少元素
//容量=第三个值减去第一个值
//长度=第二个值减去第一个值
//s1 := s[1:3:5]
//fmt.Println(s1) // 3 5 6
//fmt.Println(cap(s1))
//fmt.Println(len(s1))
//s1 := s[:]
//fmt.Println(s1) //[3 5 6 7 8 9]
//fmt.Println(len(s1)) //6
//fmt.Println(cap(s1)) //6
//s1 := s[3:]
//fmt.Println(s1) //[7 8 9]
//fmt.Println(len(s1)) //3
//fmt.Println(cap(s1)) //3
//s1 := s[:3]
//fmt.Println(s1) //[3 5 6]
//fmt.Println(len(s1)) //3
//fmt.Println(cap(s1)) //6是切片s的容量
s1 := s[1:3]
fmt.Println(s1) //[5 6]
fmt.Println(len(s1)) //2
fmt.Println(cap(s1)) //5
切片值的修改
切片截取后返回新切片,对新切片的值进行修改,会影响原切片吗?
会影响。
s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s[0] = 30
fmt.Println(s) //[30 2 3 4 5 6 7 8 9 10]
s1 := s[2:5]
fmt.Println(s1) //[3 4 5]
s1[0] = 40
fmt.Println(s) //[30 2 40 4 5 6 7 8 9 10]
fmt.Println("s1 = ", s1) //s1 = [40 4 5]
s1只是指向切片s
append函数的使用
一般扩容方式为上一次:容量*2, 如果超过1024字节 每次扩容上一次的1/4
s := make([]int, 5, 8) //len是5
fmt.Println(s)
fmt.Println(len(s)) //5
fmt.Println(cap(s)) //8
s = append(s, 1)
fmt.Println(s)
fmt.Println(len(s)) //6
fmt.Println(cap(s)) //8
s = append(s, 2)
fmt.Println(s)
fmt.Println(len(s)) //7
fmt.Println(cap(s)) //8
s = append(s, 3)
fmt.Println(s)
fmt.Println(len(s)) //8
fmt.Println(cap(s)) //8
s = append(s, 4)
fmt.Println(s)
fmt.Println(len(s)) //9
fmt.Println(cap(s)) //16
copy函数
copy(切片1,切片2)
注意事项:拷贝的长度为两个切片中长度较小的长度值。
s1 := []int{1, 2}
s2 := []int{3, 4, 5, 6, 7}
//copy(s1, s2) //将s2拷贝到s1中去
//fmt.Println(s1) //[3 4] 拷贝是原有位置相同的两个值
copy(s2, s1)
fmt.Println(s2) //[1 2 5 6 7]
切片作为函数参数,切片是引用类型
func Init(num []int) {
for i := 0; i < len(num); i++ {
num[i] = i
}
}
func main() {
//s := []int{1, 2, 3, 4, 5}
s := make([]int, 10)
Init(s)
fmt.Println(s) //[0 1 2 3 4 5 6 7 8 9]
}
冒泡排序
s := []int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
var temp int
for i := 0; i < len(s)-1; i++ { //十个数比较9趟
for j := 0; j < len(s)-1-i; j++ { //交换多少次
if s[j] > s[j+1] {
temp = s[j]
s[j] = s[j+1]
s[j+1] = temp
}
}
}
fmt.Println(s)
选择排序
//考虑第一趟的情况
//找出切片中最小的数据
//和切片中的第一个数进行位置交换
s := []int{5, 9, 0, 2, 7}
for j := 0; j < len(s)-1; j++ { //比较趟数
min := s[j] //假设最小
minIndex := j //最小值的下标
for i := j + 1; i < len(s); i++ {
if min > s[i] {
min = s[i]
minIndex = i //记录一下下标
}
}
if minIndex != j {
s[j], s[minIndex] = s[minIndex], s[j]
}
}
fmt.Println(s)
map概念
Go语言中的字典结构是有键和值构成的。
所谓的键,就类似于新华字典的部首或拼音,可以快速查询出对应的数据。
字典中的键是不允许重复的,就像身份证号一样
map 是一种无序的键值对的集合。
map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
map创建与初始化
var m map[int]string = map[int]string{1: "ziye", 2: "woai", 3: "ni"} //键不能重复
fmt.Println(m) //map[1:ziye 2:woai 3:ni]
m1 := map[int]string{1: "ziye", 2: "woai", 3: "ni"}
fmt.Println(m1) //map[1:ziye 2:woai 3:ni]
m2 := make(map[string]int)
fmt.Println(m2) //map[]
m3 := make(map[string]int, 10)
m3["ziye"] = 1
m3["lisi"] = 2
m3["wangwu"] = 3
fmt.Println(m3) //map[lisi:2 wangwu:3 ziye:1]
fmt.Println(len(m3)) //0 返回的是map中已有的键值对个数
m3["ziye"] = 5
fmt.Println(m3) //map[lisi:2 wangwu:3 ziye:5] 完成数据的修改
map键与值
通过key获取值时,判断是否存在
变量1,变量2 := map名字[键]
如果键是存在的”变量1”中存储对应的值,并”变量2”的值为true,否则为false
var m map[int]string = map[int]string{1: "王五", 2: "李四"}
fmt.Println(m[2]) //李四
value, ok := m[1]
if ok {
fmt.Println(value)
} else {
fmt.Println("不存在")
}
通过for…range方式进行遍历
var m map[int]string = map[int]string{1: "王五", 2: "李四"}
for key, value := range m {
fmt.Println(key) //键
fmt.Println(value) //值
}
通过key删除某个值
delete(map名字,键)
var m map[int]string = map[int]string{1: "王五", 2: "李四"}
delete(m, 2)
fmt.Println(m)
map作为函数参数—引用类型
在函数中修改map的值,会影响到原map
func PrintMap(m map[int]string) {
for key, value := range m {
fmt.Println(key)
fmt.Println(value)
}
}
func DeleteMap(m map[int]string) {
delete(m, 2)
}
func main() {
var m map[int]string = map[int]string{1: "王五", 2: "李四"}
fmt.Println(m)
PrintMap(m)
DeleteMap(m)
fmt.Println(m) //map[1:王五]
PrintMap(m)
}
结构体简介
通过定义变量的信息,进行存储,这种方式,比较麻烦,并且不利于数据的管理。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体可以很好地管理一批有联系的数据,使用结构体可以提高程序的易读性
结构体的创建与初始化
//成员名称前面不能添加var
type Student struct {
id int
name string
age int
addr string
}
var s Student = Student{1, "ziye", 18, "bj"} //顺序初始化
fmt.Println(s) //{1 ziye 18 bj}
//部分初始化
var s1 Student = Student{name: "ziye", age: 18}
fmt.Println(s1) //{0 ziye 18 }
//通过“结构体变量.成员” 完成初始化
var stu Student
stu.id = 102
stu.name = "ziye"
stu.age = 18
stu.addr = "wh"
fmt.Println(stu) //{102 ziye 18 wh}
结构体与数组
package main
import "fmt"
// Student 成员名称前面不能添加var
type Student struct {
id int
name string
age int
addr string
}
func main() {
var arr [3]Student = [3]Student{
{1, "ziye", 18, "bj"},
{2, "ziye1", 18, "bj"},
{3, "ziye2", 18, "bj"},
}
fmt.Println(arr) //[{1 ziye 18 bj} {2 ziye1 18 bj} {3 ziye2 18 bj}]
fmt.Println(arr[0]) //{1 ziye 18 bj}
fmt.Println(arr[0].age) //18
arr[0].age = 20
fmt.Println(arr)
//通过循环来输出结构体数组的内容
//for i := 0; i < len(arr); i++ {
// fmt.Println(arr[i])
//}
for key, value := range arr {
fmt.Println(key)
fmt.Println(value)
}
}
结构体与切片
var s []Student = []Student{
{1, "ziye", 18, "bj"},
{2, "ziye1", 18, "bj"},
{3, "ziye2", 18, "bj"},
}
//fmt.Println(s[0])
//fmt.Println(s[0].age)
//s[0].age = 20
//fmt.Println(s)
//
循环遍历
//for i := 0; i < len(s); i++ {
// fmt.Println(s[i].name)
//}
//
//for key, value := range s {
// fmt.Println(key)
// fmt.Println(value.id)
//}
s = append(s, Student{19, "aaa", 18, "bj"})
fmt.Println(s)
结构体与map
package main
import "fmt"
// Student 成员名称前面不能添加var
type Student struct {
id int
name string
age int
addr string
}
func main() {
m := make(map[int]Student)
m[1] = Student{1, "ziye", 18, "bj"}
m[2] = Student{2, "ziye1", 18, "bj"}
//fmt.Println(m)
//fmt.Println(m[1].name)
delete(m, 1)
for key, value := range m {
fmt.Println(key)
fmt.Println(value.name)
}
}
结构体作为函数的参数
在函数中修改结构体成员值,不会影响到原结构体—值传递
package main
import "fmt"
// Student 成员名称前面不能添加var
type Student struct {
id int
name string
age int
addr string
}
func PrintDemo(stu Student) {
fmt.Println(stu)
stu.age = 20
}
func main() {
stu := Student{1, "ziye", 18, "bj"}
PrintDemo(stu)
fmt.Println(stu)
}
输出年龄最大的学生的详细信息
package main
import "fmt"
// Student 成员名称前面不能添加var
type Student struct {
id int
name string
age int
addr string
}
func InitData(stu []Student) {
for i := 0; i < len(stu); i++ {
fmt.Printf("请输入%d个学生的详细信息\n", i+1)
fmt.Scan(&stu[i].id, &stu[i].name, &stu[i].age, &stu[i].addr)
}
}
func GexMax(stu []Student) {
var max int = stu[0].age
var maxIndex int //记录最大年龄学生信息在整个切片中下标
for i := 0; i < len(stu); i++ {
if stu[i].age > max {
max = stu[i].age
maxIndex = i
}
}
fmt.Println(stu[maxIndex])
}
func main() {
stu := make([]Student, 3) //结构体切片
InitData(stu)
GexMax(stu)
}
指针简介
在函数中修改变量值,会影响到原有变量的值吗?
指针也是一个变量,但它是一种特殊的变量,因为它存储的数据不仅仅是一个普通的值,如简单的整数或字符串,而是另一个变量的内存地址。
内存地址
指针的定义
var 指针变量名 *类型
指针间接修改变量的值
指针变量 = 值
var a int = 10
var p *int
p = &a //拿到变量a的内存地址
fmt.Printf("%p\n", &a) //0xc00000a188
fmt.Printf("%p\n", p) //0xc00000a188
fmt.Printf("%p\n", &p) //0xc000050038 ===>p的内存地址
fmt.Println(*p) //根据地址取出相对应的值 10
*p = 222
fmt.Println(a) //222
指针操作注意事项
1:空接口
var p *int
fmt.Println(p) //nil
2:不要操作没有合法指向的内存
var p *int
*p = 78 // invalid memory address or nil pointer dereference
fmt.Println(p)
3:new 函数使用
开辟数据类型对应的内存空间 返回值为数据类型指针
var p *int
p = new(int) //开辟数据类型的内存空间
*p = 78
fmt.Println(p)
fmt.Println(*p)
指针变量作为函数参数
package main
import "fmt"
func main() {
var num int = 10
fmt.Println(num) //10
Update(&num)
fmt.Println(num) //60
}
func Update(num *int) {
*num = 60
}
数组指针
var 数组指针变量 *[下标] 类型
package main
import "fmt"
func UpdateArr(p *[10]int) {
p[0] = 100
}
func main() {
nums := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var p *[10]int //指针变量
p = &nums
//fmt.Println(p)
//fmt.Println(*p) //*p获取整个数组中的内容
//fmt.Println((*p)[0]) //先算*p []运算优先级高于*
//fmt.Println(p[0]) //简化了
//
//for i := 0; i < len(p); i++ {
// fmt.Printf("%d = ", p[i])
//}
UpdateArr(p)
fmt.Println(*p) //会进行修改
}
指针数组
数组元素是指针类型
指针数组指的是一个数组中存储的都是指针(也就是地址)。也就是一个存储了地址的数组。
根据具体地址获取对应的值
- 指针数组名[下标]
var p [2]*int //指针数组
var i int = 10
var j int = 20
p[0] = &i
p[1] = &j
fmt.Println(p) //[0xc00000a188 0xc00000a1a0]
fmt.Println(*p[0]) //10 不要加[]
fmt.Println(*p[1])
//for i := 0; i < len(p); i++ {
// fmt.Println(*p[i])
//}
for key, value := range p {
fmt.Println(key) // 0 1
fmt.Println(value) //打印地址
fmt.Println(*value) //取值
}
指针与切片
定义指针,指向切片
s := []int{1, 2, 3, 4, 5, 6}
var p *[]int
p = &s //切片指针p指向了切片s
//fmt.Println(*p) //[1 2 3 4 5 6]
//fmt.Println(&p)
//fmt.Println((*p)[0])
//fmt.Println(&s[0]) //0xc00000e480
//fmt.Println(p[0]) 切片不支持这种写法
(*p)[0] = 200
//fmt.Println(s) //[200 2 3 4 5 6]
//
//for i := 0; i < len(*p); i++ {
// fmt.Println((*p)[i])
//}
for key, value := range *p {
fmt.Println("key = ", key) //下标
fmt.Println("vakue = ", value) //对应的值
}
指针与结构体
package main
import "fmt"
type Student struct {
id int
name string
age int
}
func UpdateStudent(p *Student) {
p.name = "ziyeye"
}
func main() {
stu := Student{1, "ziye", 18}
var p *Student
p = &stu
//fmt.Println(*p)
//fmt.Println(p)
//fmt.Println(&p) //0xc000050038
//
//fmt.Println((*p).name) //ziye
//
//fmt.Println(p.name) //ziye
//
//p.age = 20
//
//fmt.Println(stu) //{1 ziye 20}
//fmt.Println(*p)
UpdateStudent(p)
fmt.Println(stu)
}
多级指针
var a int = 10
var p *int //一级指针
p = &a
var pp **int //二级指针 //可以用来保存一级指针的内存地址
pp = &p
**pp = 200
fmt.Println(a) //200
深浅拷贝
浅拷贝:仅仅拷贝的是变量的值,没有对指向的空间进行任何的拷贝
深拷贝:将原有的变量的空间全部拷贝一份。
go语言中赋值,函数传参, 函数返回值都是浅拷贝。
浅拷贝
package main
import "fmt"
func main() {
var num int = 10
ap := &num
Update(ap)
fmt.Println(num)
}
func Update(p *int) {
*p = 60
}
函数中修改切片值影响原有切片原因分析
package main
import "fmt"
func main() {
s := make([]int, 5, 5)
Modify(s)
fmt.Println(s)
}
func Modify(sli []int) {
for i := 0; i < 5; i++ {
// sli[i] = i //这个是指向一个指针,这样会影响到原有切片
sli = append(sli, i) //这样不会影响到原有的切片
}
fmt.Println("sli:",sli)
}
通讯录案例源码
package main
import "fmt"
func scanNum() {
//1:给出相应的操作提示
fmt.Println("添加联系人信息,请按1")
fmt.Println("删除联系人信息,请按2")
fmt.Println("查询联系人信息,请按3")
fmt.Println("编辑联系人信息,请按4")
//2:对用户输入的数字进行判断
var num int //保存用户输入的数字
_, _ = fmt.Scan(&num)
switchType(num)
}
type person struct {
userName string
addressPhone map[string]string //key 表示电话类型,value:电话
}
// 保存多个联系人的信息
var personList = make([]person, 0)
// 添加联系人
func addPerson() {
//姓名,电话号码
//定义结构体表示联系人的信息
//定义切片保存多个人的联系信息
var name string
var address string
var phone string
var exit string //表示退出电话的录入
var addressPhone = make(map[string]string) //保存电话的类型和电话,电话类型作为key
//添加姓名
fmt.Println("请输入姓名")
_, _ = fmt.Scan(&name)
for {
//保存电话类型
fmt.Println("请输入电话类型")
_, _ = fmt.Scan(&address)
//保存电话号码
fmt.Println("请输入电话号码")
_, _ = fmt.Scan(&phone)
//将电话以及电话类型存储到addressPhone中
addressPhone[address] = phone
fmt.Println("如果结束电话的录入,请按Q")
_, _ = fmt.Scan(&exit)
if exit == "Q" {
break
} else {
continue
}
}
//将联系人的信息存储到切片中 //向切片中保存数据
personList = append(personList, person{name, addressPhone})
//fmt.Println(personList)
showPersonList() //调用函数展示联系人的信息
}
// 删除联系人的操作
func deletePerson() {
var name string
index := -1 // 记录找到的联系人信息在切片中的下标
//输入要删除的联系人的信息
fmt.Println("输入要删除的联系人姓名")
_, _ = fmt.Scan(&name)
//判断切片是否存储了要删除的联系人的信息
for i := 0; i < len(personList); i++ {
if name == personList[i].userName {
//记录要删除的联系人信息在切片中的位置(下标)
index = i
break
}
}
//删除操作 // index = 3 // 5,6,7,9,10,11,12
if index != -1 {
personList = append(personList[:index], personList[index+1:]...) //append 函数第二个参数如果是切片后面要给三个点
}
showPersonList()
}
// 查找联系人信息
func findPerson() *person {
//1 输入要查询的联系人信息
var name string
index := -1 // 记录找到的联系人信息在切片中的下标
fmt.Println("请输入要查询的联系人姓名:")
_, _ = fmt.Scan(&name)
//2 根据输入的联系人姓名,查找对应的联系信息
for key, studentValue := range personList { //可以存在名字相同
if studentValue.userName == name {
index = key //从数据中取出下标
fmt.Println("联系人姓名:", studentValue.userName)
for PhoneType, Phone := range studentValue.addressPhone {
fmt.Printf("%s:%s\n", PhoneType, Phone)
}
//break
}
}
//3 打印输出结果
if index == -1 {
fmt.Println("没有找到联系人信息")
return nil
} else {
return &personList[index]
}
}
// 编辑联系人信息
func editPerson() {
// 1:查找到要编辑的联系人信息
var name string //存储新的联系人姓名
var p *person
p = findPerson() //找到联系人地址
var num int //存储修改数据的类型
var menu = make([]string, 0) //保存电话类型,方便后面修改
var pNum int // 编辑的电话类型编号
var phone string // 新的电话号码
if p != nil {
for {
fmt.Println("编辑用户名称请按:5,编辑电话请按:6,退出请按:7")
_, _ = fmt.Scan(&num)
switch num {
case 5:
//修改联系人姓名
fmt.Println("请输入新的姓名")
_, _ = fmt.Scan(&name)
p.userName = name
showPersonList()
case 6:
//编辑联系电话
//1:展示联系人所有的电话信息
var j int
for PhoneType, Phone := range p.addressPhone {
fmt.Println("编辑(", PhoneType, ")", Phone, "请按: ", j)
j++
menu = append(menu, PhoneType)
}
fmt.Println("请输入编辑号码的类型")
_, _ = fmt.Scan(&pNum)
//2 完成修改
for index, PhoneType := range menu {
if index == pNum {
fmt.Println("请输入新的电话号码")
_, _ = fmt.Scan(&phone)
p.addressPhone[PhoneType] = phone
}
}
}
if num == 7 {
break
}
}
} else {
fmt.Println("没有找到要编辑的联系人信息")
}
// 进行编辑
}
// 展示切片中存储的联系人的信息
func showPersonList() {
// 1 判断一下切片中是否有数据
if len(personList) == 0 {
fmt.Println("暂时没有联系人信息")
} else {
// 2 可以通过循环方式打印切片中的数据
for _, value := range personList {
fmt.Println("联系人姓名: ", value.userName)
for address, phone := range value.addressPhone {
fmt.Println("电话类型:", address)
fmt.Println("电话号码", phone)
}
}
}
}
// 对输入的内容进行判断,决定执行那块操作
func switchType(n int) {
switch n {
case 1:
//添加联系人的操作
addPerson()
case 2:
//删除联系人的操作
deletePerson()
case 3:
//查询联系人的操作
findPerson()
case 4:
//编辑联系人的操作
editPerson()
}
}
func main() {
for {
scanNum()
}
}