阶段1 Go语言基础Day03 函数错误处理

Posted 澐湮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阶段1 Go语言基础Day03 函数错误处理相关的知识,希望对你有一定的参考价值。

day03

函数

package main

import "fmt"

//导入包(标准包,自定义包,第三方包)

//包级别的变量,常量,函数

//无参 无返回值
func sayHello() 
	fmt.Println("Hello World")


//有参 无返回值
func sayHi(name string, name2 string) 
	fmt.Println("Hi", name, name2)


//有参 有返回值
func add(n1 int, n2 int) int 
	return n1 + n2


func test(a int, b string) 
	fmt.Println(a, b)


func main() 
	//sayHello

	//调用 方法名()
	sayHello()
	sayHi("aa", "bb")
	n := add(1, 2)
	fmt.Println(n)

	test(1, "cc")


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run func.go
Hello World
Hi aa bb
3
1 cc
*/

参数

参数合并
package main

import "fmt"

//参数类型合并
//连续多个变量类型相同
// 保留最后一个元素类型,前面的类型都可以省略

func add(n1, n2 int) int 
	return n1 + n2


func test(p1, p2 string, p3, p4 int, p5, p6 bool) 
	fmt.Printf("%T,%T,%T,%T,%T,%T\\n", p1, p2, p3, p4, p5, p6)
	fmt.Println(p1, p2, p3, p4, p5, p6)


func main() 
	fmt.Println(add(1, 2))
	test("", "", 0, 0, false, false)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run params.go
3
string,string,int,int,bool,bool
  0 0 false false
*/
可变参数
package main

import "fmt"

//可变参数的函数

func test(args ...string) 
	fmt.Printf("%T,%#v\\n", args, args)


//1.可变参数 在一个方法中只能有一个
//2.并且可变参数必须放在函数声明参数列表最后

//举例(函数至少有n个参数)
//add(n1,n2,...)
func add(n1, n2 int, args ...int) int 
	total := n1 + n2

	for _, v := range args 
		total += v
	
	return total



func main() 
	test()
	test("1")
	test("1", "2", "3")

	fmt.Println(1, 2)
	fmt.Println(1, 2, 3)
	fmt.Println(1, 2, 3, 4)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run args.go
[]string,[]string(nil)
[]string,[]string"1"
[]string,[]string"1", "2", "3"
1 2
1 2 3
1 2 3 4
*/
解切片
package main

import "fmt"

//可变参数的函数

func test(args ...string) 
	fmt.Printf("%T,%#v\\n", args, args)


//1.可变参数 在一个方法中只能有一个
//2.并且可变参数必须放在函数声明参数列表最后

//举例(函数至少有n个参数)
//add(n1,n2,...)
func add(n1, n2 int, args ...int) int 
	total := n1 + n2

	for _, v := range args 
		total += v
	
	return total


func calc(n1, n2 int, args ...int) int 
	//直接调用add把add方法结果进行返回
	//args切片
	// switch(len(args))
	//add(n1,n2,args[0],args[1]...)
	return add(n1, n2, args...) //解操作


func main() 
	// test()
	// test("1")
	// test("1", "2", "3")

	// fmt.Println(1, 2)
	// fmt.Println(1, 2, 3)
	// fmt.Println(1, 2, 3, 4)
	params := []int1, 2, 3, 4, 5, 6, 7
	fmt.Println(add(1, 2, params...))



/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run args.go
31
*/

返回值

多返回值&命名返回值&合并返回值类型
package main

import "fmt"

func add(n1, n2 int) int 
	return n1 + n2


func mult(n1, n2 int) int 
	return n1 * n2


//多返回值
func calc(n1, n2 int) (int, int) 
	//a,b:=1,2
	r1 := add(n1, n2)
	r2 := mult(n1, n2)
	return r1, r2


//命名返回值
func calc2(n1, n2 int) (r1 int, r2 int) 
	//a,b:=1,2
	r1 = add(n1, n2)
	r2 = mult(n1, n2)
	return


//合并返回值类型
func calc3(n1, n2 int) (r1, r2 int) 
	//a,b:=1,2
	r1 = add(n1, n2)
	r2 = mult(n1, n2)
	return


func main() 
	fmt.Println(calc(1, 2))
	fmt.Println(calc2(1, 2))
	fmt.Println(calc3(1, 2))


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run return.go
3 2
3 2
3 2
*/
值类型和引用类型
package main

import "fmt"

func main() 
	//值类型 b=a
	age := 30
	tmpAge := age
	tmpAge = 31
	fmt.Println(age, tmpAge)
	fmt.Printf("%p,%p\\n", &age, &tmpAge)

	//引用类型 b=a (地址)
	users := make([]string, 10)
	tmpUsers := users
	tmpUsers[0] = "xx"
	fmt.Printf("%#v,%#v\\n", users, tmpUsers)
	fmt.Printf("%p,%p\\n", users, tmpUsers)



/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run quote.go
30 31
0xc0000aa058,0xc0000aa070
[]string"xx", "", "", "", "", "", "", "", "", "",[]string"xx", "", "", "", "", "", "", "", "", ""
0xc0000a2140,0xc0000a2140
*/
函数使用值类型和引用类型
package main

import "fmt"

func test1(n int) 
	n = 1


func test2(s []int) 
	fmt.Printf("test2:%p\\n", s)
	s[0] = 1


func main() 
	a := 0
	b := make([]int, 10)
	test1(a)
	test2(b)
	fmt.Println(a)
	fmt.Println(b)
	fmt.Printf("main:%p\\n", b)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run quote.go
test2:0xc0000b00f0
0
[1 0 0 0 0 0 0 0 0 0]
main:0xc0000b00f0
*/
根据条件,返回不同的返回值
package main

import "fmt"

func test(flag bool) int 
	if flag 
		return 1
	
	fmt.Println("return before")
	return 2


func main() 
	fmt.Println(test(true))
	fmt.Println(test(false))


递归

阶乘
package main

import "fmt"

//阶乘
//n!=
// n=0 n!=1
// n>=1 n!=n*(n-1)!=n*(n-1)*...*1
// f(n) = n!
// f(n) = n*f(n-1)
// 分治=> 大问题分解为多个相同的小问题(小问题可以继续拆分,直到某一个可以解决的子问题)
// 递归调用=>函数直接或间接调用自己(总有一个停止的条件,)
func f(n int64) int64 
	if n == 0 
		return 1
	
	return n * f(n-1)


func main() 
	//f(3)=3*f(2)=3*2*f(1)
	fmt.Println(f(3))


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run fact.go
6
*/

汉诺塔

从start挪到end 接着temp

package main

import (
	"fmt"
)

// n个盘子 start(开始) end(终点) temp(借助)
// n start -> temp ->end
// n -1 start ->end =>temp
// start ->end
// n-1 temp -> start ->end
// 终止条件 start -> end
func tower(start string, end string, temp string, layer int) 
	if layer == 1 
		fmt.Println(start, "->", end)
		return
	
	tower(start, temp, end, layer-1)
	fmt.Println(start, "->", end)
	tower(temp, end, start, layer-1)


func main() 
	tower("塔1", "塔3", "塔2", 3)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run tower.go
塔1 -> 塔3
塔1 -> 塔2
塔3 -> 塔2
塔1 -> 塔3
塔2 -> 塔1
塔2 -> 塔3
塔1 -> 塔3
*/

函数指针传递

package main

import "fmt"

//值类型 在函数内修改实参的值
//fmt.Scan(&age)

func change(value int) 
	value += 1


func changePoint(pointer *int) 
	*pointer = *pointer + 1


func main() 
	value := 1
	change(value)
	fmt.Println(value)

	changePoint(&value)
	fmt.Println(value)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run pointer.go
1
2
*/

函数类型

package main

import "fmt"

// //无参 无返回值
// func sayHell() 
// 	fmt.Println("Hello World")
// 

// //有参 无返回值
// func sayHi(name string, name2 string) 
// 	fmt.Println("Hi:", name, name2)
// 

// //有参 有返回值
// func add(n1 int, n2 int) int 
// 	return n1 + n2
// 

func test(a int, b string) int 
	fmt.Println(a, b)
	return 1


func main() 
	//test() //函数调用
	a := test
	b := test(1, "") //执行test函数 打印 1 "" //空字符省略了
	fmt.Printf("%T\\n", test)
	fmt.Printf("%T\\n", a)
	fmt.Printf("%T\\n", b)
	a(1, "xx")

	// callback的值是nil
	var callback func(int, int) int
	fmt.Printf("%T,%#v\\n", callback, callback)



/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run type.go
1 
func(int, string) int
func(int, string) int
int
1 xx
*/

声明函数类型&类型一致赋值
package main

import "fmt"

//有参 有返回值
func add(n1 int, n2 int) int 
	return n1 + n2


func main() 
    
	// callback的值是nil
	var callback func(int, int) int
	fmt.Printf("%T,%#v\\n", callback, callback)

	callback = add
	fmt.Printf("%#v\\n", callback)
	rt := callback(1, 4)
	fmt.Println(rt)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run type.go
func(int, int) int,(func(int, int) int)(nil)
(func(int, int) int)(0x76dd40)
5
*/

类型不一致不能赋值

必须一致才能赋值

//有参 有返回值
func add(n1 int, n2 int) int 
	return n1 + n2


func test(a int, b string) int 
	fmt.Println(a, b)
	return 1



高阶函数

函数作为参数 funcparams.go
package main

import "fmt"

func calc(n1 int, n2 int, callback func(int, int) int) int 
	//不定义什么运算
	//通过函数参数传递要进行的运算
	rt := callback(n1, n2)
	//检查结果在0,100范围内,超过-1
	if rt >= 0 && rt <= 100 
		return rt
	
	return -1


func add(n1, n2 int) int 
	return n1 + n2


func mult(n1, n2 int) int 
	return n1 * n2


func main() 
	rt := calc(1, 2, add)
	fmt.Println(rt)

	rt = calc(1, 2, mult)
	fmt.Println(rt)

	rt = calc(50, 30, add)
	fmt.Println(rt)

	rt = calc(50, 30, mult)
	fmt.Println(rt)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run funcparams.go
3
2
80
-1
*/

匿名函数

匿名函数示例 lambda.go
示例1
package main

import "fmt"

func calc(n1 int, n2 int, callback func(int, int) int) int 
	//不定义什么运算
	//通过函数参数传递我要进行运算
	rt := callback(n1, n2)
	if rt >= 0 && rt <= 100 
		return rt
	
	return -1


func main() 
	add := func(n1, n2 int) int 
		return n1 + n2
	
	mult := func(n1, n2 int) int 
		return n1 * n2
	
	rt := calc(1, 2, add)
	fmt.Println(rt)
	rt = calc(1, 2, mult)
	fmt.Println(rt)
	rt = calc(50, 30, add)
	fmt.Println(rt)



示例2 直接引入
package main

import "fmt"

func calc(n1 int, n2 int, callback func(int, int) int) int 
	//不定义什么运算
	//通过函数参数传递我要进行运算
	rt := callback(n1, n2)
	if rt >= 0 && rt <= 100 
		return rt
	
	return -1


func main() 
	// add := func(n1, n2 int) int 
	// 	return n1 + n2
	// 
	// mult := func(n1, n2 int) int 
	// 	return n1 * n2
	// 
	// rt := calc(1, 2, add)
	// fmt.Println(rt)
	// rt = calc(1, 2, mult)
	// fmt.Println(rt)
	// rt = calc(50, 30, add)
	// fmt.Println(rt)

	rt := calc(50, 30, func(n1, n2 int) int 
		return n1 + n2
	)
	fmt.Println(rt)
	rt = calc(50, 30, func(n1, n2 int) int 
		return n1 * n2
	)
	fmt.Println(rt)

/*
D:\\GoWork\\src\\go_course\\day03-20230306>go run lambda.go
80
-1
*/

示例3 局部初始化
package main

import "fmt"

func main() 
	func() 
		fmt.Println("call")
	()
	fmt.Println("1")

/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run lambda2.go
call
1
*/

匿名函数中作用域

函数fun(name string) 内没有声明desc 使用外部的,做修改了

示例1
package main

import "fmt"

func main() 
	name, desc := "xx", "i\'m xx"
	func(name string) 
		fmt.Println(name, desc)
	("aa")
	fmt.Println(name)

/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run block.go
aa i\'m xx
xx
*/

示例2
package main

import "fmt"

func main() 
	name, desc := "xx", "i\'m xx"
	func(name string) 
		fmt.Println(name, desc)
		name, desc = "bb", "cc"
		fmt.Println(name, desc)
	("aa")
	fmt.Println(name, desc)


示例3 作用域 中声明
package main

import "fmt"

func main() 
	name, desc := "xx", "i\'m xx"
	func(name string) 
		fmt.Println(name, desc)
		name, desc := "bb", "cc"
		fmt.Println(name, desc)
	("aa")
	fmt.Println(name, desc)

/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run block.go
aa i\'m xx
bb cc
xx i\'m xx
*/

高阶函数
函数作为返回值 - 闭包 close.go
示例1
package main

import "fmt"

func addBase(base int) func(int) int 
	fmt.Println(base)
	return func(n int) int 
		return n
	


func main() 
	addBase(1)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run close.go
1
*/

示例2
package main

import "fmt"

func addBase(base int) func(int) int 
	fmt.Println(base)
	return func(n int) int 
		return n + base
	


func main() 
	add1 := addBase(1)
	fmt.Println(add1(5))

	add10 := addBase(10)
	fmt.Println(add10(3))


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run close.go
1
6
10
13
*/

匿名函数应用

sort.Slice
package main

import (
	"fmt"
	"sort"
)

func main() 
	// char => counter
	// A=>65
	// B=>66
	// C=>67
	// D=>68
	stats := [][]int\'A\', 3, \'B\', 2, \'c\', 1, \'D\', 2
	//使用出现的次数进行排序
	sort.Slice(stats, func(i, j int) bool 
		return stats[i][1] > stats[j][1]
	)
	fmt.Println(stats)



sort.SliceStable
package main

import (
	"fmt"
	"sort"
)

func main() 
	// char => counter
	// A=>65
	// B=>66
	// C=>67
	// D=>68
	stats := [][]int\'A\', 3, \'B\', 2, \'c\', 1, \'D\', 2
	//使用出现的次数进行排序
    // B,2,D,2=> 稳定的
    // D,2,B,2=> 不稳定的
	sort.Slice(stats, func(i, j int) bool 
		return stats[i][1] > stats[j][1]
	)
	// sort.SliceStable(stats, func(i, j int) bool 
	// 	return stats[i][1] > stats[j][1]
	// )
	fmt.Println(stats)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run sort.go
[[65 3] [66 2] [68 2] [99 1]]
*/

sort.Search
package main

import (
	"fmt"
	"sort"
)

func main() 
	// char => counter
	// A=>65
	// B=>66
	// C=>67
	// D=>68
	stats := [][]int\'A\', 3, \'B\', 2, \'c\', 1, \'D\', 2
	//使用出现的次数进行排序
	sort.Slice(stats, func(i, j int) bool 
		return stats[i][1] > stats[j][1]
	)
	// sort.SliceStable(stats, func(i, j int) bool 
	// 	return stats[i][1] > stats[j][1]
	// )
	fmt.Println(stats)

	//升序 <=
	//降序 >=
	// 对stats升序排序<=,查询stats[i][1]是1的元素的索引 是3
	index := sort.Search(len(stats), func(i int) bool 
		return stats[i][1] <= 1
	)
	fmt.Println(index)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run sort.go
[[65 3] [66 2] [68 2] [99 1]]
3
*/


练习 todolist

// 做一个命令行的任务管理
// 用户管理

// 1 函数,输入&输出,符合数据结构
// 2 了解流程(对数据的操作流程,增、删、改、查)


// 1 任务的输入(添加任务)
// 2 任务列表(任务查询)
// 3 任务修改
// 4 任务删除
// 5 详情

// 任务
// ID,任务名称,开始时间,结束时间,状态,负责人
// ID,name,start_time,end_time,status,user
// []map[string][string]

示例1-新增功能

1 创建todos map切片
2 添加常量(任务名 ...)

任务名 开始、结束时间 状态 用户名 等

3 添加newTask函数
4 通过scan获取,append加入切片
package main

import "fmt"

var todos = make([]map[string]string, 0)

const (
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func newTask() map[string]string 
	task := make(map[string]string)
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


func main() 
	var text string
	task := newTask()
	task[endTime] = ""
	task[status] = "新创建"

	fmt.Println("请输入任务信息:")
	fmt.Print("任务名:")
	fmt.Scan(&text)
	task[name] = text

	fmt.Print("开始时间:")
	fmt.Scan(&text)
	task[startTime] = text

	fmt.Print("负责人:")
	fmt.Scan(&text)
	task[user] = text

	todos = append(todos, task)
	fmt.Println(todos)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306\\todolist>go run add.go
请输入任务信息:
任务名:todo01
开始时间:19:00
负责人:tt
[map[end_time: name:todo01 start_time:19:00 status:新创建 user:tt]]
*/

示例1-新增扩展

1 添加数据到todos map切片
package main

import (
	"fmt"
	"strconv"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",



2 添加常量(id 完成 ...)

​ 完成、未完成、id等字段

package main

import (
	"fmt"
	"strconv"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

3 添加genId函数

字符串转换为int

todoId, _ := strconv.Atoi(todo["id"])

func genId() int 
	var rt int
	for _, todo := range todos 
		todoId, _ := strconv.Atoi(todo["id"])
		if rt < todoId 
			rt = todoId
		
	
	return rt + 1


4 函数newTask添加task[id]
func newTask() map[string]string 
	//id生成(用todos中最大的ID+1)
	task := make(map[string]string)
	task[id] = strconv.Itoa(genId())
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


5 新增功能测试
package main

import (
	"fmt"
	"strconv"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func genId() int 
	var rt int
	for _, todo := range todos 
		todoId, _ := strconv.Atoi(todo["id"])
		if rt < todoId 
			rt = todoId
		
	
	return rt + 1


func newTask() map[string]string 
	//id生成(用todos中最大的ID+1)
	task := make(map[string]string)
	task[id] = strconv.Itoa(genId())
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


func main() 
	var text string
	task := newTask()
	task[endTime] = ""
	task[status] = "新创建"

	fmt.Println("请输入任务信息:")
	fmt.Print("任务名:")
	fmt.Scan(&text)
	task[name] = text

	fmt.Print("开始时间:")
	fmt.Scan(&text)
	task[startTime] = text

	fmt.Print("负责人:")
	fmt.Scan(&text)
	task[user] = text

	todos = append(todos, task)
	fmt.Println(todos)



/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306\\todolist>go run add.go
请输入任务信息:
任务名:做饭
开始时间:19:00
负责人:xx
[map[end_time: id:1 name:陪孩子散步 start_time:18:00 status:未完成 user:xx] map[end_time: id:2 name:备课 start_time:21:00 status:未完成 user:xx] map[end_time: id:4 name:复习 start_time:09:00 status:未完成 user:xx] map[end_time: id:5 name:做饭 start_time:19:00 status:新创建 user:xx]]
*/


示例2 查询功能 query.go

1 补充数据到todos map切片
// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "5", "name": "准备上课", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "6", "name": "课堂笔记", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


2 添加打印函数(分割符strings.Repeat)
func printTask(task map[string]string) 
	fmt.Println(strings.Repeat("-", 20))
	fmt.Println("ID", task[id])
	fmt.Println("任务名:", task[name])
	fmt.Println("开始时间:", task[startTime])
	fmt.Println("完成时间:", task[endTime])


3 查询todo[name]字段,包含某个字符串
func main() 
	var text string
	fmt.Print("请输入查询信息:")
	fmt.Scan(&text)
	for _, todo := range todos 
		if strings.Contains(todo[name], text) 
			printTask(todo)
		
	


4 查询功能测试
package main

import (
	"fmt"
	"strings"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "5", "name": "准备上课", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "6", "name": "课堂笔记", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func printTask(task map[string]string) 
	fmt.Println(strings.Repeat("-", 20))
	fmt.Println("ID", task[id])
	fmt.Println("任务名:", task[name])
	fmt.Println("开始时间:", task[startTime])
	fmt.Println("完成时间:", task[endTime])


func main() 
	var text string
	fmt.Print("请输入查询信息:")
	fmt.Scan(&text)
	for _, todo := range todos 
		if strings.Contains(todo[name], text) 
			printTask(todo)
		
	



/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306\\todolist>go run query.go
请输入查询信息:课
--------------------
ID 2
任务名: 备课
开始时间: 21:00
完成时间:
--------------------
ID 5
任务名: 准备上课
开始时间: 09:00
完成时间:
--------------------
ID 6
任务名: 课堂笔记
开始时间: 09:00
完成时间:
*/

示例3 todolist.go

1 复制代码到todolist.go
共有部分:
	复制todos变量,复制常量,
add.go部分:
	复制genId函数,复制newTask函数 
query.go部分:
	复制printTask函数

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "5", "name": "准备上课", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "6", "name": "课堂笔记", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func genId() int 
	var rt int
	for _, todo := range todos 
		todoId, _ := strconv.Atoi(todo["id"])
		if rt < todoId 
			rt = todoId
		
	
	return rt + 1


func newTask() map[string]string 
	//id生成(用todos中最大的ID+1)
	task := make(map[string]string)
	task[id] = strconv.Itoa(genId())
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


func printTask(task map[string]string) 
	fmt.Println(strings.Repeat("-", 20))
	fmt.Println("ID", task[id])
	fmt.Println("任务名:", task[name])
	fmt.Println("开始时间:", task[startTime])
	fmt.Println("完成时间:", task[endTime])


2 新增for循环
选择功能 if else
func main() 
	for 
		fmt.Print("请输入操作(add/query/..../):")
		var text string
		fmt.Scan(&text)

		if text == "add" 
		 else if text == "query" 
		 else if text == "modify" 
		 else if text == "delete" 
		 else 
			fmt.Println("输入指令不正确")
		
	


改为switch case
func main() 
	for 
		fmt.Print("请输入操作(add/query/..../):")
		var text string
		fmt.Scan(&text)

		// if text == "add" 
		//  else if text == "query" 
		//  else if text == "modify" 
		//  else if text == "delete" 
		//  else 
		// 	fmt.Println("输入指令不正确")
		// 
		switch text 
		case "add":
		case "query":
		case "modify":
		case "delete":
		default:
			fmt.Println("输入指令错误")
		
	


3 完善for循环
添加任务代码
		case "add":
			var text string
			task := newTask()
			fmt.Println("请输入任务信息:")
			fmt.Print("任务名:")
			fmt.Scan(&text)
			task[name] = text

			fmt.Print("开始时间:")
			fmt.Scan(&text)
			task[startTime] = text

			fmt.Print("负责人:")
			fmt.Scan(&text)
			task[user] = text

			todos = append(todos, task)
			fmt.Println("创建任务成功")
		case "query":

查询任务代码
		case "query":
			var text string
			fmt.Print("请输入查询信息:")
			fmt.Scan(&text)
			for _, todo := range todos 
				if strings.Contains(todo[name], text) 
					printTask(todo)
				
			
		case "modify":

测试添加和查询
/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306\\todolist>go run todolist.go
请输入操作(add/query/..../):add
请输入任务信息:
任务名:做饭
开始时间:15:00
负责人:xx
创建任务成功
请输入操作(add/query/..../):query
请输入查询信息:饭
--------------------
ID 7
任务名: 做饭
开始时间: 15:00
完成时间:
请输入操作(add/query/..../):
*/

添加退出功能

break跳出switch层,没有跳出for层,使用label退出。或者打印exit后return

func main() 
EXIT:
	for 
		fmt.Print("请输入操作(add/query/..../exit/):")
		var text string
		fmt.Scan(&text)

		switch text 
		case "add":
			/*......*/
		case "query":
			/*......*/
		case "modify":
		case "delete":
		case "exit":
			fmt.Println("exit")
			break EXIT
		default:
			fmt.Println("输入指令错误")
		
	


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306\\todolist>go run todolist.go
请输入操作(add/query/..../):exit
exit

*/

第一阶段 完整代码

package main

import (
	"fmt"
	"strconv"
	"strings"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "5", "name": "准备上课", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "6", "name": "课堂笔记", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func genId() int 
	var rt int
	for _, todo := range todos 
		todoId, _ := strconv.Atoi(todo["id"])
		if rt < todoId 
			rt = todoId
		
	
	return rt + 1


func newTask() map[string]string 
	//id生成(用todos中最大的ID+1)
	task := make(map[string]string)
	task[id] = strconv.Itoa(genId())
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


func printTask(task map[string]string) 
	fmt.Println(strings.Repeat("-", 20))
	fmt.Println("ID", task[id])
	fmt.Println("任务名:", task[name])
	fmt.Println("开始时间:", task[startTime])
	fmt.Println("完成时间:", task[endTime])


func main() 

	for 
		fmt.Print("请输入操作(add/query/..../exit/):")
		var text string
		fmt.Scan(&text)

		// if text == "add" 
		//  else if text == "query" 
		//  else if text == "modify" 
		//  else if text == "delete" 
		//  else 
		// 	fmt.Println("输入指令不正确")
		// 
		switch text 
		case "add":
			var text string
			task := newTask()
			fmt.Println("请输入任务信息:")
			fmt.Print("任务名:")
			fmt.Scan(&text)
			task[name] = text

			fmt.Print("开始时间:")
			fmt.Scan(&text)
			task[startTime] = text

			fmt.Print("负责人:")
			fmt.Scan(&text)
			task[user] = text

			todos = append(todos, task)
			fmt.Println("创建任务成功")
		case "query":
			var text string
			fmt.Print("请输入查询信息:")
			fmt.Scan(&text)
			for _, todo := range todos 
				if strings.Contains(todo[name], text) 
					printTask(todo)
				
			
		case "modify":
		case "delete":
		case "exit":
			fmt.Println("exit")
			// break EXIT
			return
		default:
			fmt.Println("输入指令错误")
		
	


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306\\todolist>go run todolist.go
请输入操作(add/query/..../exit/):add 
请输入任务信息:
任务名:上课
开始时间:09:00
负责人:xx
创建任务成功
请输入操作(add/query/..../exit/):query
请输入查询信息:课
--------------------
ID 2
任务名: 备课
开始时间: 21:00
完成时间:
--------------------
ID 5
任务名: 准备上课
开始时间: 09:00
完成时间:
--------------------
ID 6
任务名: 课堂笔记
开始时间: 09:00
完成时间:
--------------------
ID 7
任务名: 上课
开始时间: 09:00
完成时间:
请输入操作(add/query/..../exit/):exit
exit
*/

代码抽象为函数
func add() 
	var text string
	task := newTask()
	fmt.Println("请输入任务信息:")
	fmt.Print("任务名:")
	fmt.Scan(&text)
	task[name] = text

	fmt.Print("开始时间:")
	fmt.Scan(&text)
	task[startTime] = text

	fmt.Print("负责人:")
	fmt.Scan(&text)
	task[user] = text

	todos = append(todos, task)
	fmt.Println("创建任务成功")


func query() 
	var text string
	fmt.Print("请输入查询信息:")
	fmt.Scan(&text)
	for _, todo := range todos 
		if strings.Contains(todo[name], text) 
			printTask(todo)
		
	


//调用
...
		switch text 
		case "add":
			add()
		case "query":
			query()
		case "modify":
...

重复代码再提取input

重复部分:声明text 打印操作信息,scan接收变量指针,返回text内容赋值

func input(prompt string) string 
	var text string
	fmt.Print(prompt)
	fmt.Scan(&text)
	return strings.TrimSpace(text)


package main

import (
	"fmt"
	"strconv"
	"strings"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "5", "name": "准备上课", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "6", "name": "课堂笔记", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func input(prompt string) string 
	var text string
	fmt.Print(prompt)
	fmt.Scan(&text)
	return strings.TrimSpace(text)


func genId() int 
	var rt int
	for _, todo := range todos 
		todoId, _ := strconv.Atoi(todo["id"])
		if rt < todoId 
			rt = todoId
		
	
	return rt + 1


func newTask() map[string]string 
	//id生成(用todos中最大的ID+1)
	task := make(map[string]string)
	task[id] = strconv.Itoa(genId())
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


func printTask(task map[string]string) 
	fmt.Println(strings.Repeat("-", 20))
	fmt.Println("ID", task[id])
	fmt.Println("任务名:", task[name])
	fmt.Println("开始时间:", task[startTime])
	fmt.Println("完成时间:", task[endTime])


func add() 
	//var text string
	task := newTask()
	fmt.Println("请输入任务信息:")
	// fmt.Print("任务名:")
	// fmt.Scan(&text)
	// task[name] = text
	task[name] = input("任务名:")

	// fmt.Print("开始时间:")
	// fmt.Scan(&text)
	// task[startTime] = text
	task[startTime] = input("开始时间:")

	// fmt.Print("负责人:")
	// fmt.Scan(&text)
	// task[user] = text
	task[user] = input("负责人:")

	todos = append(todos, task)
	fmt.Println("创建任务成功")


func query() 
	// var text string
	// fmt.Print("请输入查询信息:")
	// fmt.Scan(&text)
	q := input("请输入查询信息:")

	for _, todo := range todos 
		// if strings.Contains(todo[name], text) 
		if strings.Contains(todo[name], q) 
			printTask(todo)
		
	


func main() 

	for 
		// fmt.Print("请输入操作(add/query/..../exit/):")
		// var text string
		// fmt.Scan(&text)
		text := input("请输入操作(add/query/..../exit/):")

		// if text == "add" 
		//  else if text == "query" 
		//  else if text == "modify" 
		//  else if text == "delete" 
		//  else 
		// 	fmt.Println("输入指令不正确")
		// 
		switch text 
		case "add":
			add()
		case "query":
			query()
		case "modify":
		case "delete":
		case "exit":
			fmt.Println("exit")
			// break EXIT
			return
		default:
			fmt.Println("输入指令错误")
		
	


省略变量,再提取
package main

import (
	"fmt"
	"strconv"
	"strings"
)

// var todos = make([]map[string]string, 0)
var todos = []map[string]string
	"id": "1", "name": "陪孩子散步", "start_time": "18:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "2", "name": "备课", "start_time": "21:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "4", "name": "复习", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "5", "name": "准备上课", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",
	"id": "6", "name": "课堂笔记", "start_time": "09:00", "end_time": "", "status": statusNew, "user": "xx",


const (
	statusNew      = "未完成"
	statusComplete = "完成"
)

const (
	id        = "id"
	name      = "name"
	startTime = "start_time"
	endTime   = "end_time"
	status    = "status"
	user      = "user"
)

func input(prompt string) string 
	var text string
	fmt.Print(prompt)
	fmt.Scan(&text)
	return strings.TrimSpace(text)


func genId() int 
	var rt int
	for _, todo := range todos 
		todoId, _ := strconv.Atoi(todo["id"])
		if rt < todoId 
			rt = todoId
		
	
	return rt + 1


func newTask() map[string]string 
	//id生成(用todos中最大的ID+1)
	task := make(map[string]string)
	task[id] = strconv.Itoa(genId())
	task[name] = ""
	task[startTime] = ""
	task[endTime] = ""
	task[status] = "新创建"
	task[user] = ""
	return task


func printTask(task map[string]string) 
	fmt.Println(strings.Repeat("-", 20))
	fmt.Println("ID", task[id])
	fmt.Println("任务名:", task[name])
	fmt.Println("开始时间:", task[startTime])
	fmt.Println("完成时间:", task[endTime])


func add() 
	task := newTask()
	fmt.Println("请输入任务信息:")
	task[name] = input("任务名:")
	task[startTime] = input("开始时间:")
	task[user] = input("负责人:")

	todos = append(todos, task)
	fmt.Println("创建任务成功")


func query() 
	//q := input("请输入查询信息:")

	for _, todo := range todos 
        //if strings.Contains(todo[name], q) 
		if strings.Contains(todo[name], input("请输入查询信息:")) 
			printTask(todo)
		
	


func main() 

	for 
		//text := input("请输入操作(add/query/..../exit/):")

		//switch text 
   		switch input("请输入操作(add/query/..../exit/):") 
		case "add":
			add()
		case "query":
			query()
		case "modify":
		case "delete":
		case "exit":
			fmt.Println("exit")
			return
		default:
			fmt.Println("输入指令错误")
		
	


第二阶段 重构v2

func main() 

	methods := map[string]func()
		"add":   add,
		"query": query,
	

	for 
		text := input("请输入操作(add/query/..../exit/):")

		// switch text 
		// case "add":
		// 	add()
		// case "query":
		// 	query()
		// case "modify":
		// case "delete":
		// case "exit":
		// 	fmt.Println("exit")
		// 	return
		// default:
		// 	fmt.Println("输入指令错误")
		// 
		if text == "exit" 
			break
		
		method, ok := methods[text]
		if ok 
			method()
		 else 
			fmt.Println("输入指令不正确")
		
	


改写为1行
func main() 

	methods := map[string]func()
		"add":   add,
		"query": query,
	

	for 
		text := input("请输入操作(add/query/..../exit/):")

		if text == "exit" 
			break
		

		if method, ok := methods[text]; ok 
			method()
		 else 
			fmt.Println("输入指令不正确")
		
	


作业

1 知识整理
2 我有一个梦想 中出现次数最多的top 10 字符集出现次数
3 统计
	a 每个IP出现次数
	b 每个状态码出现次数
	c 每个IP在每个URL上产生的流量
	
int[][4]string
   // ip url 状态码 字节大小
   "1.1.1.1","/index.html","200","1000",
   "1.1.1.2","/index.html","200","10000",
   "1.1.1.1","/index.html","200","10000"


key:map 必须是可以使用==进行比较的数据类型
key 数据类型,ip+url =>string key
	[]stringip,url
	[2]stringip,url
4 todo管理
	a 编辑
		请输入编辑的ID
		通过ID查找=>Task =>显示
		用户确认是否进行编辑(y/yes):编辑
		用户输入:任务名称,开始时间,状态
		//状态如果是已完成,初始化完成时间
		//time.Now().Format("2006-01-02 15:04:05")
	b删除
		请输入编辑的ID
		通过ID查找 =>Task =>显示
		用户确认是否进行删除(y/yes):删除
	c数据验证(用户输入数据检查)
		任务名称:不能重复(新增,编辑)
		编辑:
			a,任务名称不变
			b. 任务名称改成其他已存在的
		任务状态:
			新创建,开始执行,已完成,暂停
			

错误处理

package main

import (
	"errors"
	"fmt"
	"strconv"
)

func div(n1, n2 int) (int, error) 
	if n2 == 0 
		return -1, errors.New("除数为0")
	
	return n1 / n2, nil


func main() 
	value, err := strconv.Atoi("xxx")
	fmt.Printf("%T\\n", err)
	fmt.Println(err)
	fmt.Println(value)

	e := fmt.Errorf("自定义错误")
	fmt.Printf("%T %#v\\n", e, e)

	e2 := errors.New("自定义错误2")
	fmt.Printf("%T %#v\\n", e2, e2)

	//go语言
	//希望程序内部如果有错误
	//通过最后一个返回值显示返回给调用者
	//由调用者决定如何处理
	if rt, err := div(1, 0); err == nil 
		fmt.Println(rt)
	 else 
		fmt.Println(err)
	


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run error.go
*strconv.NumError
strconv.Atoi: parsing "xxx": invalid syntax
0
*errors.errorString &errors.errorStrings:"自定义错误"
*errors.errorString &errors.errorStrings:"自定义错误2"
除数为0
*/

延迟声明main()函数中 defer

package main

import "fmt"

func main() 
	//defer 函数调用
	// 延迟执行,在函数退出之前
	defer func() 
		fmt.Println("defer")
	()
	defer func() 
		fmt.Println("defer A")
	()
	defer func() 
		fmt.Println("defer B")
	()
	fmt.Println("main")



延迟声明test()函数中 defer

package main

import "fmt"

func test() string 
	//defer 函数调用
	// 延迟执行,在函数退出之前
	defer func() 
		fmt.Println("defer")
	()
	defer func() 
		fmt.Println("defer A")
	()
	defer func() 
		fmt.Println("defer B")
	()
	fmt.Println("test")
	return "test--"


func main() 
	fmt.Println(test())

/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run defer.go
test
defer B
defer A
defer
test--
*/

延迟声明defer中不要修改返回值

package main

import "fmt"

func test() (rt string) 
	//defer 函数调用
	// 延迟执行,在函数退出之前
	defer func() 
		fmt.Println("defer")
		rt = "defer"
	()
	defer func() 
		fmt.Println("defer A")
	()
	defer func() 
		fmt.Println("defer B")
	()
	fmt.Println("test")
	rt = "test--"
	return


func main() 
	fmt.Println(test())

/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run defer.go
test
defer B
defer A
defer
defer
*/

defer使用

package main

import "fmt"

func test() (rt string) 
	//defer 函数调用
	// 延迟执行,在函数退出之前
	defer func() 
		fmt.Println("defer")
		rt = "defer"
	()
	defer func() 
		fmt.Println("defer A")
	()
	defer func() 
		fmt.Println("defer B")
	()
	fmt.Println("test")
	rt = "test--"
	return


func test2(n1, n2 int) 
	defer func() 
		//函数体内不管是否发生错误,都会执行
		fmt.Println("test2 defer")
	()
	fmt.Println("before")
	fmt.Println(n1 / n2)
	fmt.Println("after")


func main() 
	fmt.Println(test())
	test2(1, 0)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run defer.go
test
defer B
defer A
defer
defer
before
test2 defer
panic: runtime error: integer divide by zero

goroutine 1 [running]:
main.test2(0x1, 0x0)
        D:/GoWork/src/go_course/day03-20230306/defer.go:29 +0x146
main.main()
        D:/GoWork/src/go_course/day03-20230306/defer.go:35 +0x65
exit status 2
*/

defer在for循环中使用 forerror.go
package main

import "fmt"

func main() 
	for i := 0; i < 3; i++ 
		fmt.Println("for before", i)
		//打开文件
		//延迟关闭
		//处理(处理出现错误)
		defer func() 
			fmt.Println("defer", i)
		()
		fmt.Println("for after", i)
	
	fmt.Println("main")


D:\\GoWork\\src\\go_course\\day03-20230306>go run forerror.go
for before 0
for after 0
for before 1
for after 1
for before 2
for after 2
main
defer 3
defer 3
defer 3

处理

在for循环中defer ,导致for循环一直使用defer 函数没有退出,一直没有释放defer

处理:单独添加一个func函数,在函数中defer

package main

import "fmt"

func main() 
	for i := 0; i < 3; i++ 
		func ()
			//打开文件
			//延迟关闭
         	 //   defer 
			//处理
		()
		fmt.Println("for before", i)
		defer func() 
			fmt.Println("defer", i)
		()
		fmt.Println("for after", i)
	
	fmt.Println("main")



使用赋值1
package main

import "fmt"

func main() 
	for i := 0; i < 3; i++ 
		a := i
		fmt.Println("for before", i)
		defer func() 
			fmt.Println("defer", a)
		()
		fmt.Println("for after", i)
	
	fmt.Println("main")


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run forerror.go
for before 0
for after 0
for before 1
for after 1
for before 2
for after 2
main
defer 2
defer 1
defer 0
*/

使用局部定义的i
package main

import "fmt"

func main() 
	for i := 0; i < 3; i++ 

		fmt.Println("for before", i)
		defer func(i int) 
			fmt.Println("defer", i)
		(i)
		fmt.Println("for after", i)
	
	fmt.Println("main")


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run forerror.go
for before 0
for after 0
for before 1
for after 1
for before 2
for after 2
main
defer 2
defer 1
defer 0
*/

panic

package main

import "fmt"

func test() 
	fmt.Println("before")
	panic("自定义panic")
	fmt.Println("after")


func main() 
	test()


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before
panic: 自定义panic

goroutine 1 [running]:
main.test()
        D:/GoWork/src/go_course/day03-20230306/panic.go:7 +0x65
main.main()
        D:/GoWork/src/go_course/day03-20230306/panic.go:12 +0x17
exit status 2
*/

defer在panic前
package main

import "fmt"

func test() 
	defer func() 
		fmt.Println("defer")
	()
	fmt.Println("before")
	panic("自定义panic")
	fmt.Println("after")


func main() 
	test()


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before
defer
panic: 自定义panic

goroutine 1 [running]:
main.test()
        D:/GoWork/src/go_course/day03-20230306/panic.go:10 +0x8b
main.main()
        D:/GoWork/src/go_course/day03-20230306/panic.go:15 +0x17
exit status 2
*/

使用recover并打印类型

package main

import "fmt"

func test() 
	// recover 必须在延迟执行函数内
	defer func() 
		fmt.Println("defer")
		err := recover()
		//打印类型
		fmt.Printf("%T,%#v\\n", err, err)
	()
	fmt.Println("before")
	panic("自定义panic")
	fmt.Println("after")


func main() 
	fmt.Println("before main")
	test()
	fmt.Println("after main")


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before main
before
defer
string,"自定义panic"
after main
*/

没有发生panic,仍然执行recover
package main

import "fmt"

func test() 
	// recover 必须在延迟执行函数内
	defer func() 
		fmt.Println("defer")
		err := recover()
		//打印类型
		fmt.Printf("%T,%#v\\n", err, err)
	()
	fmt.Println("before")
	// panic("自定义panic")
	fmt.Println("after")


func main() 
	fmt.Println("before main")
	test()
	fmt.Println("after main")


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before main
before
after
defer
<nil>,<nil>
after main
*/

修改增加判断
package main

import "fmt"

func test() 
	// recover 必须在延迟执行函数内
	defer func() 
		fmt.Println("defer")
		//打印类型
		if err := recover(); err != nil 
			fmt.Printf("%T,%#v\\n", err, err)
		
	()
	fmt.Println("before")
	// panic("自定义panic")
	fmt.Println("after")


func main() 
	fmt.Println("before main")
	test()
	fmt.Println("after main")


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before main
before
after
defer
after main
*/

返回值,接收err返回
package main

import "fmt"

func test() (err error) 
	// recover 必须在延迟执行函数内
	defer func() 
		fmt.Println("defer")
		//打印类型
		if panicErr := recover(); panicErr != nil 
			err = fmt.Errorf("%s", panicErr)
		
	()
	fmt.Println("before")
	panic("自定义panic")
	fmt.Println("after")
	return err


func main() 
	fmt.Println("before main")
	err := test()
	fmt.Println("after main", err)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before main
before
defer
after main 自定义panic
*/

errors.New()
package main

import (
	"errors"
	"fmt"
)

func test() (err error) 
	// recover 必须在延迟执行函数内
	defer func() 
		fmt.Println("defer")
		//打印类型
		if panicErr := recover(); panicErr != nil 
			err = fmt.Errorf("%s", panicErr)
		
	()
	fmt.Println("before")
	// panic("自定义panic")
	err = errors.New("xxx")
    //检查所有的数据,连接,资源。。。
    //用别人的库的时候,panic
	fmt.Println("after")
	return err


func main() 
	fmt.Println("before main")
	err := test()
	fmt.Println("after main", err)


/*打印结果
D:\\GoWork\\src\\go_course\\day03-20230306>go run panic.go
before main
before
after
defer
after main xxx
*/

了解gopath

//D:\\GoWork\\src\\go_course\\day03-20230306\\main\\main.go
package main

import "fmt"

var mainVar = "man Var"

func mainFunc() 
	fmt.Println("main func")


func main() 
	mainFunc()
	utilsFunc()
	fmt.Println(mainVar)
	fmt.Println(utilsVar)

//D:\\GoWork\\src\\go_course\\day03-20230306\\main\\utils.go
package main

import "fmt"

var utilsVar = "utils Var"

func utilsFunc() 
	fmt.Println("utils Func")



/*打印结果
1 关闭set GO111MODULE=off
2 D:\\GoWork\\src\\go_course\\day03-20230306\\main>go build 
3 D:\\GoWork\\src\\go_course\\day03-20230306\\main>main.exe
main func
utils Func
man Var
utils Var
*/

// GO PATH项目
// GOPATH GOMODULE
// GO包
// 1.同一个文件夹下所有go文件的包名,必须一致
// 2. 关闭了 GOMODULE
// GOPATH在项目目录直接运行go build无文件名
// 将当前文件夹下的所有go文件进行编译
// 3. main包编译为可执行程序
// 4. main包中只能有一个main函数

// GOPATH 环境变量信息,定义多个目录
// src ==> 源文件
// pkg ==> 程序编译的包文件
// bin ==> 程序编译的可执行文件

测试使用
go build test
go install test
/*路径结构
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\bin\\
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\pkg\\
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src\\test\\main.go
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src\\test\\test.go
*/

/*执行结果
D:\\GoWork\\src\\go_course\\day03-20230306\\main>set GOPATH=D:\\GoWork\\src\\go_course\\day03-20230306\\main;%GOPATH%  
D:\\GoWork\\src\\go_course\\day03-20230306\\main>echo %GOPATH%
D:\\GoWork\\src\\go_course\\day03-20230306\\main;D:\\GoWork
D:\\GoWork\\src\\go_course\\day03-20230306\\main>cd src
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src>ls -la
total 0
drwxr-xr-x 1 zhu 197121 0  3月 12 16:25 .
drwxr-xr-x 1 zhu 197121 0  3月 12 16:25 ..
drwxr-xr-x 1 zhu 197121 0  3月 12 16:25 test
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src>go build test
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src>test.exe
main func
utils Func
man Var
utils Var
*/

/*执行 go install test 相当于生成test.go 后拷贝到bin目录下
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src>go install test
*/


go install pkg
package pkg

var utilsVar = "utils Var"

/*打印结果
文件及目录:
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src\\pkg\\utils.go
执行:
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src>go install pkg
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\src>

使用 go install pkg 会在pkg下生成pkg.a文件
D:\\GoWork\\src\\go_course\\day03-20230306\\main\\pkg\\windows_amd64\\pkg.a
*/

注意 包内和包外 函数名大小写问题

Go语言开发Go语言错误处理

Go语言开发(七)、Go语言错误处理

一、defer延迟函数

1、defer延迟函数简介

defer在声明时不会立即执行,而是在函数return后,再按照FILO(先进后出)的原则依次执行每一个defer,一般用于异常处理、释放资源、清理数据、记录日志等。
每次defer语句执行时,defer修饰的函数的返回值和参数取值会照常进行计算和保存,但是defer修饰的函数不会执行。等到上一级函数返回前,会按照defer的声明顺序倒序执行全部defer的函数。defer所修饰函数的任何返回值都会被丢弃。
如果一个defer所修饰函数的值为nil,则defer的函数会在函数执行时panic(异常),而不会在defer语句执行时panic。defer所修饰函数的上一级函数即使抛出异常,defer所修饰函数也会被执行的,确保资源被合法释放。
defer延迟函数使用示例如下:

package main

import "fmt"

func deferTest(){
   defer fmt.Println(1)
   defer fmt.Println(2)
   fmt.Println(3)
}

func main() {
   deferTest()//3,2,1
}

2、defer延迟函数应用

A、简化资源回收

mu.Lock() 
defer mu.Unlock()

defer?有一定的开销, 为了节省性能可以避免使用的defer?
B、捕获panic异常
Go语言中,panic用于抛出异常,,recover用于捕获异常。
recover只能在defer语句中使用,直接调用recover是无效的。

package main

import "fmt"

func deferRecover(){
   defer func () {
      if r := recover(); r != nil {
         fmt.Println("recover")
      }
   }()
   fmt.Println("exception will be happen")
   panic("exception has happped.")
   fmt.Println("return normally")
}

func main() {
   deferRecover()
}

C、修改返回值
defer可以用于在?return?后修改函数的返回值。

package main

import "fmt"

func deferReturn(a,b int)(sum int){
   defer func(){
      sum += 100
   }()
   sum = a + b
   return sum
}

func main() {
   sum := deferReturn(1,6)
   fmt.Println(sum)//107
}

D、安全回收资源

func set(mu *sync.Mutex, arr []int, i, v int) {
   mu.Lock()
   defer mu.Unlock()
   arr[i] = v
}

如果运行时抛出切片越界异常,可以保证mu.Unlock()被调用。

二、错误处理

1、错误处理简介

Go语言通过内置的错误接口提供了简单的错误处理机制。
error类型是一个接口类型,定义如下:

type error interface {
    Error() string}

Golang中引入error接口类型作为错误处理的标准模式,如果函数要返回错误,则返回值类型列表中肯定包含error。

2、错误处理使用

package main

import (
   "fmt"
   "errors"
)

//定义一个DivideError类型
type DivideError struct {
   dividee int
   divider int
}
//实现error接口
func (err *DivideError) Error() error{
   strFormat := `Cannot proceed, the divider is zero.
dividee: %d 
divider: 0`
   return errors.New(fmt.Sprintf(strFormat, err.dividee))
}
//定义除法运算
func divide(vardividee int, vardivider int)(result int, errmsg error){
   if vardivider == 0{
      divideErr := DivideError{
         dividee:vardividee,
         divider:vardivider,
      }
      errmsg = divideErr.Error()
      return 0,errmsg
   }else{
      return vardividee/vardivider,nil
   }
}

func main() {
   //正常情况
   if result, err := divide(100, 10); err != nil{
      fmt.Println(err)
   }else{
      fmt.Println("100/10 = ", result)
   }
   //当被除数为零的时候会返回错误信息
   if _, errorMsg := divide(100, 0); errorMsg != nil{
      fmt.Println(errorMsg)
   }
}

三、异常处理

1、异常处理简介

Go使用panic()函数抛出异常,在defer语句中调用recover()函数捕获异常。

func panic(interface{})//接受任意类型参数 无返回值 
func recover() interface{}//可以返回任意类型 无参数

panic()是一个内置函数,可以中断原有的控制流程,进入一个panic流程中。当函数F调用panic,函数F的执行被中断,但F中的延迟函数(必须是在panic前的已加载的defer)会正常执行,然后F函数逐层向上返回,直到发生panic的goroutine中所有调用的函数返回,此时程序退出。异常可以直接调用panic产生,也可以由运行时错误产生,例如访问越界的数组。
recover()是一个内置函数,可以让进入panic流程中的goroutine恢复过来。recover仅在延迟函数中有效。在正常的执行过程中,调用recover会返回nil,并且没有其它任何效果。如果当前的goroutine陷入panic,调用recover可以捕获到panic的输入值,并且恢复正常的执行。
一般情况下,recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(使用recover关键字),会导致goroutine所属的进程打印异常信息后直接退出。

2、异常处理使用示例

package main

import (
   "errors"
   "fmt"
)

//定义一个DivideError类型
type DivideError struct {
   dividee int
   divider int
}
//实现error接口
func (err *DivideError) Error() error{
   strFormat := `Cannot proceed, the divider is zero.
dividee: %d 
divider: 0`
   return errors.New(fmt.Sprintf(strFormat, err.dividee))
}

//定义除法运算
func divide(dividee int, divider int)(result int){
   defer func() {
      if r := recover();r != nil{
         divideErr := DivideError{
            dividee:dividee,
            divider:divider,
         }
         fmt.Println(divideErr.Error())
      }
   }()
   result = dividee/divider
   return result
}

func main() {
   a := divide(100,0)
   fmt.Println(a)
}

以上是关于阶段1 Go语言基础Day03 函数错误处理的主要内容,如果未能解决你的问题,请参考以下文章

go基础编程 day-1

阶段1 Go语言基础Day04 包管理 常用模块 单元测试

Go语言开发Go语言错误处理

Go语言学习之路目录

Go语言函数语法下篇

Go语言函数语法下篇