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