异常处理
Go语言追求简洁优雅 所以 不支持传统的 try…catch…finally 这种异常
Go语言的设计者认为 将异常与控制结构混在一起 使 代码变得混乱
因为开发者 容易滥用异常 甚至一个小小的错误都抛出一个异常
Go语言 用多值返回 来返回错误 不用异常代替错误 更不要用来 控制流程
在极个别的情况下 才使用Go中引入的 Exception 处理 defer panic recover
panic
1 内建函数
2 假如函数F 书写 panic语句 会终止其后要执行的代码 在panic所在函数F内 如果存在要执行的 defer函数列表 按照 defer 逆序执行
3 返回函数F的调用者G 在G中 调用函数F语句之后的代码不会执行 假如函数G中存在要执行的defer函数列表 按照defer的逆序执行 这里的 defer 有点类似 try-catch-finally 中的 finally
4 直到goroutine整个退出 并报告错误
recover
2 用来控制一个 goroutine 的 panicking 行为 捕获 panic 从而影响应用的行为
3 一般的调用建议
a) 在defer函数中 通过 recever 来终止一个 gojroutine 的 panicking 过程 从而恢复正常代码的执行
b) 可以获取通过 panic 传递的 error
简单 讲
Go语言 可以抛出一个 panic 异常 然后在 defer 中通过 recover 捕获这个异常 然后正常处理
示例
main 函数相当于调用者 G
f函数相当于函数F
func main() {
fmt.Println("c")
defer func() { // 必须要先声明 defer 否则不能捕获到 panic 异常
fmt.Println("d")
if err := recover(); err != nil {
fmt.Println(err) // 这里的 err 其实 是 panic 传入的内容
}
fmt.Println("e")
}()
f() //开始调用f
fmt.Println("f") //这里开始下面代码不会再执行
func f() {
fmt.Println("a")
panic("异常信息")
fmt.Println("b") //这里开始下面代码不会再执行
-------output-------
c
a
d
异常信息
e
利用 recover 处理 panic 指令 defer 必须在 panic 之前声明 否则当 panic 时 recover 无法捕获到 panic
package main
import (
"fmt"
)
defer func() {
fmt.Println("1")
fmt.Println(err)
panic("fault")
fmt.Println("2")
运行结果
fault
1
程序首先运行 panic 出现故障 跳转到包含 recover() 的 defer 函数执行 recover 捕获 panic 此时 panic 就不继续传递
但是 recover 后 程序并 不 返回到 panic 点继续执行以后的动作 而是在 recover 这个点继续执行以后的动作 即执行上面的 defer 函数 输出 1
利用 recover 处理 panic 指令 必须利用 defer 在 panic 之前声明 否则当 panic 时 recover 无法捕获到 panic 无法防止 panic 扩散
回收处理
GO 中 defer 代码块 在函数调用链表中 增加一个函数调用 这个函数调用不是普通的函数调用 是会在函数正常返回 也就是return 后添加一个函数调用 因此 defer通常用来释放函数内部变量
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
defer src.Close()
dst, err := os.Create(dstName)
defer dst.Close()
return io.Copy(dst, src)
通过 defer 在代码中 关闭/清理 代码 所 用 变量 defer作为golang清理变量的特性 有 独有且明确的行为
defer 三条使用规则
当defer被声明时 其参数就会被实时解析 即defer的参数的变量值 在代码中defer使用后的位置改变并不会对改变defer用到的值
defer执行顺序为先进后出 在函数中 先定义的defer将会后执行
defer可以读取有名返回值
defer代码块的作用域仍然在函数之内 因此defer仍然可以读取函数内的变量
Go 语言 Select 与 for 合 用时可能 的坑
func test(){
i := 0
for {
select {
case <-time.After(time.Second * time.Duration(2)):
i++
if i == 5{
fmt.Println("break now")
break
fmt.Println("inside the select: ")
fmt.Println("inside the for: ")
执行后发现 居然break不出去 当for 和 select结合使用时 break语言是无法跳出for 的 因此 要break出来 需要加一个标签 使用 goto 或者 break 到具体的位置
解决方法一 使用golang中break的特性 在外层for加一个标签
ForEnd:
break ForEnd
解决方法二 使用goto直接跳出循环
goto ForEnd
ForEnd:
成功走出 坑
go get golang.org/x 包失败解决方法
国内使用 go get 安装 golang 官方包 失败
解决方法
golang 在 github 上
镜像库
https://github.com/golang/net
是 https://golang.org/x/net
获取 golang.org/x/net 包 需要以下步骤
命令行里依次输入
mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/net.git
其它 golang.org/x 下的包获取皆可使用该方法
很多go的软件在编译时使用tools
使用下面方法获取
git clone https://github.com/golang/tools.git
一定要保持与go get获取的目录结构是一致的
否则库就找不到
把握生命里每一次感动 和心爱的朋友热情相拥
感谢您的支持,我会继续努力的!
支付宝扫一扫,即可进行扫码打赏哦
2223Go 错误处理
异常处理
Go语言追求简洁优雅 所以 不支持传统的 try…catch…finally 这种异常
Go语言的设计者认为 将异常与控制结构混在一起 使 代码变得混乱
因为开发者 容易滥用异常 甚至一个小小的错误都抛出一个异常
Go语言 用多值返回 来返回错误 不用异常代替错误 更不要用来 控制流程
在极个别的情况下 才使用Go中引入的 Exception 处理 defer panic recover
panic
1 内建函数
2 假如函数F 书写 panic语句 会终止其后要执行的代码 在panic所在函数F内 如果存在要执行的 defer函数列表 按照 defer 逆序执行
3 返回函数F的调用者G 在G中 调用函数F语句之后的代码不会执行 假如函数G中存在要执行的defer函数列表 按照defer的逆序执行 这里的 defer 有点类似 try-catch-finally 中的 finally
4 直到goroutine整个退出 并报告错误
recover
1 内建函数
2 用来控制一个 goroutine 的 panicking 行为 捕获 panic 从而影响应用的行为
3 一般的调用建议
a) 在defer函数中 通过 recever 来终止一个 gojroutine 的 panicking 过程 从而恢复正常代码的执行
b) 可以获取通过 panic 传递的 error
简单 讲
Go语言 可以抛出一个 panic 异常 然后在 defer 中通过 recover 捕获这个异常 然后正常处理
示例
main 函数相当于调用者 G
f函数相当于函数F
func main() {
fmt.Println("c")
defer func() { // 必须要先声明 defer 否则不能捕获到 panic 异常
fmt.Println("d")
if err := recover(); err != nil {
fmt.Println(err) // 这里的 err 其实 是 panic 传入的内容
}
fmt.Println("e")
}()
f() //开始调用f
fmt.Println("f") //这里开始下面代码不会再执行
}
func f() {
fmt.Println("a")
panic("异常信息")
fmt.Println("b") //这里开始下面代码不会再执行
}
-------output-------
c
a
d
异常信息
e
利用 recover 处理 panic 指令 defer 必须在 panic 之前声明 否则当 panic 时 recover 无法捕获到 panic
package main
import (
"fmt"
)
func main() {
defer func() {
fmt.Println("1")
}()
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
panic("fault")
fmt.Println("2")
}
运行结果
fault
1
程序首先运行 panic 出现故障 跳转到包含 recover() 的 defer 函数执行 recover 捕获 panic 此时 panic 就不继续传递
但是 recover 后 程序并 不 返回到 panic 点继续执行以后的动作 而是在 recover 这个点继续执行以后的动作 即执行上面的 defer 函数 输出 1
利用 recover 处理 panic 指令 必须利用 defer 在 panic 之前声明 否则当 panic 时 recover 无法捕获到 panic 无法防止 panic 扩散
2222Go 错误处理
回收处理
GO 中 defer 代码块 在函数调用链表中 增加一个函数调用 这个函数调用不是普通的函数调用 是会在函数正常返回 也就是return 后添加一个函数调用 因此 defer通常用来释放函数内部变量
示例
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
通过 defer 在代码中 关闭/清理 代码 所 用 变量 defer作为golang清理变量的特性 有 独有且明确的行为
defer 三条使用规则
当defer被声明时 其参数就会被实时解析 即defer的参数的变量值 在代码中defer使用后的位置改变并不会对改变defer用到的值
defer执行顺序为先进后出 在函数中 先定义的defer将会后执行
defer可以读取有名返回值
defer代码块的作用域仍然在函数之内 因此defer仍然可以读取函数内的变量
2215Go 语言 select 语句
Go 语言 Select 与 for 合 用时可能 的坑
func test(){
i := 0
for {
select {
case <-time.After(time.Second * time.Duration(2)):
i++
if i == 5{
fmt.Println("break now")
break
}
fmt.Println("inside the select: ")
}
fmt.Println("inside the for: ")
}
}
执行后发现 居然break不出去 当for 和 select结合使用时 break语言是无法跳出for 的 因此 要break出来 需要加一个标签 使用 goto 或者 break 到具体的位置
解决方法一 使用golang中break的特性 在外层for加一个标签
func test(){
i := 0
ForEnd:
for {
select {
case <-time.After(time.Second * time.Duration(2)):
i++
if i == 5{
fmt.Println("break now")
break ForEnd
}
fmt.Println("inside the select: ")
}
fmt.Println("inside the for: ")
}
}
解决方法二 使用goto直接跳出循环
func test(){
i := 0
for {
select {
case <-time.After(time.Second * time.Duration(2)):
i++
if i == 5{
fmt.Println("break now")
goto ForEnd
}
fmt.Println("inside the select: ")
}
fmt.Println("inside the for: ")
}
ForEnd:
}
成功走出 坑
2207Go 语言问题集
go get golang.org/x 包失败解决方法
国内使用 go get 安装 golang 官方包 失败
解决方法
golang 在 github 上
镜像库
https://github.com/golang/net
是 https://golang.org/x/net
镜像库
获取 golang.org/x/net 包 需要以下步骤
命令行里依次输入
mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/net.git
其它 golang.org/x 下的包获取皆可使用该方法
很多go的软件在编译时使用tools
使用下面方法获取
git clone https://github.com/golang/tools.git
一定要保持与go get获取的目录结构是一致的
否则库就找不到
2206Go 语言问题集
把握生命里每一次感动 和心爱的朋友热情相拥