defer_test

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. //f, _ := os.OpenFile("xxx.txt")
  7. //此处有大量的逻辑需要读取文件
  8. //defer f.Close()
  9. /*
  10. defer 语句是go提供的一种用于注册延迟调用的机制 它可以让当前函数执行完毕之后执行
  11. 对于python的with语句来说
  12. */
  13. //fmt.Println("hello1")
  14. //defer a++ error 可以做函数调用不能做表达式的书写 比如a++
  15. //a := 0
  16. //defer fmt.Println("defer hello")
  17. //panic("error")
  18. //fmt.Println("hello2")
  19. //如果有多个defer会出现什么情况
  20. //defer fmt.Println("test1")
  21. //defer fmt.Println("test2")
  22. //defer fmt.Println("test3")
  23. //多个defer是按照先入后出的顺序执行的
  24. //defer 语句执行时的拷贝机制
  25. //test := func() {
  26. // fmt.Println("test1")
  27. //}
  28. //defer test()
  29. //test = func() {
  30. // fmt.Println("test2")
  31. //}
  32. //fmt.Println("test3")
  33. //
  34. //x := 10 //压栈的是函数段
  35. //defer func(a int) {
  36. // fmt.Println(x) //11
  37. // fmt.Println(a) //10
  38. //}(x)
  39. //x++
  40. //defer func(a *int) {
  41. // fmt.Println(*a)
  42. //}(&x)
  43. //x++
  44. //闭包 此处的defer函数没有参数 - 函数内部使用的值是全局的值
  45. //defer func() {
  46. // fmt.Println(x) //11
  47. //}()
  48. //x++
  49. //defer func(x int) {
  50. // fmt.Println(x) //10
  51. //}(x)
  52. //x++
  53. fmt.Println(f1()) //10 是不是就意味着 defer中影响不到外部的值呢? - 不是
  54. fmt.Println(*f2())
  55. //defer本质上是注册了一个延迟函数 defer函数的执行顺序已经确定
  56. //defer没有嵌套 defer的机制是要取代try except finally的机制
  57. }
  58. func f1() int {
  59. x := 10
  60. defer func() {
  61. x++ //闭包里面的值 不影响
  62. }()
  63. tmp := x
  64. return tmp
  65. //return x
  66. }
  67. func f2() *int {
  68. a := 10
  69. b := &a
  70. defer func() {
  71. *b++ //闭包里面的值 不影响
  72. }()
  73. temp_data := b
  74. return temp_data
  75. return b
  76. }

err_exception

  1. package main
  2. import "fmt"
  3. func div(a, b int) (int, error) {
  4. if b == 0 {
  5. panic("被除数不能为0")
  6. }
  7. return a / b, nil
  8. }
  9. func main() {
  10. //错误就是能预知到可能出现的情况,这些情况会导致你的代码出问题 参数检查 数据库访问不了
  11. //data := 12
  12. //整数转字符串 字符串的内容形式不受限制
  13. //strconv.Itoa(data) //这个Itoa的函数不可能出错 所以没有必要返回error.
  14. //内部代码出错的时候, 应该抛出异常 panic
  15. //字符串转整数 因为字符串所包含的字符集是纯数字的超集 可能会出现中文字符 标点符号等情况 故会返回error
  16. //_, err := strconv.Atoi("12") //Atoi这个函数认为我的函数内部会出现一些预知错误情况
  17. //if err != nil {
  18. // //错误
  19. //}
  20. //异常 go语言如何抛出异常和如何接收/接收异常
  21. //go语言认为错误就要自己处理,就个人而言,go语言的这种想法是正确的。但是实际使用中确实有点烦人
  22. a := 12
  23. b := 0
  24. defer func() {
  25. err := recover()
  26. if err != nil {
  27. fmt.Println("异常被捕获到")
  28. }
  29. fmt.Println("wozen")
  30. }()
  31. fmt.Println(div(a, b))
  32. //panic的坑
  33. }

func_define

package main

import (
    "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 main

import "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 map
func 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 main

import (
    "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会引起主线程的挂掉 同时会导致其他的协程都挂掉
    //为什么直接在,在父协程中无法捕获走子协程出现的异常

}