defer_test
package mainimport ( "fmt")func main() { //f, _ := os.OpenFile("xxx.txt") //此处有大量的逻辑需要读取文件 //defer f.Close() /* defer 语句是go提供的一种用于注册延迟调用的机制 它可以让当前函数执行完毕之后执行 对于python的with语句来说 */ //fmt.Println("hello1") //defer a++ error 可以做函数调用不能做表达式的书写 比如a++ //a := 0 //defer fmt.Println("defer hello") //panic("error") //fmt.Println("hello2") //如果有多个defer会出现什么情况 //defer fmt.Println("test1") //defer fmt.Println("test2") //defer fmt.Println("test3") //多个defer是按照先入后出的顺序执行的 //defer 语句执行时的拷贝机制 //test := func() { // fmt.Println("test1") //} //defer test() //test = func() { // fmt.Println("test2") //} //fmt.Println("test3") // //x := 10 //压栈的是函数段 //defer func(a int) { // fmt.Println(x) //11 // fmt.Println(a) //10 //}(x) //x++ //defer func(a *int) { // fmt.Println(*a) //}(&x) //x++ //闭包 此处的defer函数没有参数 - 函数内部使用的值是全局的值 //defer func() { // fmt.Println(x) //11 //}() //x++ //defer func(x int) { // fmt.Println(x) //10 //}(x) //x++ fmt.Println(f1()) //10 是不是就意味着 defer中影响不到外部的值呢? - 不是 fmt.Println(*f2()) //defer本质上是注册了一个延迟函数 defer函数的执行顺序已经确定 //defer没有嵌套 defer的机制是要取代try except finally的机制}func f1() int { x := 10 defer func() { x++ //闭包里面的值 不影响 }() tmp := x return tmp //return x}func f2() *int { a := 10 b := &a defer func() { *b++ //闭包里面的值 不影响 }() temp_data := b return temp_data return b}
err_exception
package mainimport "fmt"func div(a, b int) (int, error) { if b == 0 { panic("被除数不能为0") } return a / b, nil}func main() { //错误就是能预知到可能出现的情况,这些情况会导致你的代码出问题 参数检查 数据库访问不了 //data := 12 //整数转字符串 字符串的内容形式不受限制 //strconv.Itoa(data) //这个Itoa的函数不可能出错 所以没有必要返回error. //内部代码出错的时候, 应该抛出异常 panic //字符串转整数 因为字符串所包含的字符集是纯数字的超集 可能会出现中文字符 标点符号等情况 故会返回error //_, err := strconv.Atoi("12") //Atoi这个函数认为我的函数内部会出现一些预知错误情况 //if err != nil { // //错误 //} //异常 go语言如何抛出异常和如何接收/接收异常 //go语言认为错误就要自己处理,就个人而言,go语言的这种想法是正确的。但是实际使用中确实有点烦人 a := 12 b := 0 defer func() { err := recover() if err != nil { fmt.Println("异常被捕获到") } fmt.Println("wozen") }() fmt.Println(div(a, b)) //panic的坑}
func_define
package mainimport ( "errors" "fmt")//相比较其他静态语言 go语言的函数有很多两点//函数定义的几个要素: 1. 函数名 2. 参数 3. 返回值//函数第一种定义方法func add(a, b int) int { var sum int sum = a + b return sum}//函数的第二种定义方法func add2(a, b int) (sum int) { sum = a + b return sum}//函数的第三种定义方法func add3(a, b int) (sum int) { sum = a + b return}//函数的第四种定义方法//被除数为0 要返回多个值 -一个非常有用的特性//go语言的返回设置花样很多func div(a, b int) (int, error) { var result int var err error if b == 0 { err = errors.New("被除数不能为0") } else { result = a / b } return result, err}func div2(a, b int) (result int, err error) { if b == 0 { err = errors.New("被除数不能为0") } else { result = a / b } return}func main() { result, err := div2(12, 0) if err != nil { fmt.Println(err) } else { fmt.Println(result) }}
func_params
package mainimport "fmt"//省略号 ...func add(params ...int) (sum int) { //不能解决一个问题我可能有不定个int值传递进来 for _, v := range params { sum += v } return}func add2(params []int) (sum int) { //不能解决一个问题我可能有不定个int值传递进来 for _, v := range params { sum += v } params[0] = 9 return}type sub func(a, b int) int //sub就等同于 int mapfunc subImpl(a, b int) int { return a - b}func filter(score []int, f func(int) bool) []int { reSlice := make([]int, 0) for _, v := range score { if f(v) { reSlice = append(reSlice, v) } } return reSlice}func main() { //通过省略号去动态设置多个参数 fmt.Println(add(1, 2, 3)) fmt.Println(add(1, 2, 3, 4)) fmt.Println(add(1, 2, 3, 4, 5)) //这种效果 - slice //区别 slice是一种类型 还是引用传递 slice := []int{1, 2, 3, 4, 5} fmt.Println(add2(slice)) fmt.Println(add(slice...)) //将slice打散 fmt.Println(slice) //我们要慎重 //省略号的用途 //1. 函数参数不定长 2.将slice打散 3. arr := [...]int{1, 2, 3} fmt.Printf("%T\n", arr) //函数内部定义函数 函数内嵌 //匿名函数 fmt.Println(func(a, b int) int { return a + b }(1, 2)) //fmt.Printf("%T\n", result) //func(...int) int //go语言中非常重要的特性 函数 一些trick 一些语法糖 //函数的一等公民特性 - 可以作为参数 返回值 复制给另一个变量 //函数也可以当作参数传递给一个函数 var mySub sub = func(a, b int) int { return a - b } fmt.Println(mySub(1, 2)) //mySub(1, 2) //将函数作为另一个函数的参数 //写一个函数用于过滤一部分数据 score := []int{10, 30, 40, 50, 90} //写一个函数 过滤掉不合格的成绩 fmt.Println(filter(score, func(a int) bool { if a >= 90 { return true } else { return false } })) //gin python的装饰器 //go语言并没有提供try except finally //1.大量嵌套 try finally 2.打开和关闭逻辑离得太远}
http_server
package mainimport ( "fmt" "time")func f1() { defer func() { err := recover() if err != nil { fmt.Println("捕获到了") } }() go func() { panic("出错了") }() time.Sleep(2 * time.Second) //为啥panic了?}func main() { f1() //http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) { //a := 10 //b := 0 //fmt.Println(a / b) //panic("error") //go func() { //操作redis的,有人觉得这段代码可以放到协程中去运行。有一个非常大的隐患了 //panic("error") //}() //服务被停掉 //writer.Write([]byte("hello world")) //}) //http.ListenAndServe("127.0.0.1:8080", nil) //panic会引起主线程的挂掉 同时会导致其他的协程都挂掉 //为什么直接在,在父协程中无法捕获走子协程出现的异常}