16-Go语言异常处理

栏目: Go · 发布时间: 6年前

异常处理

  • 程序运行时,发生的不被期望的事件,它阻止了程序按照 程序员 的预期正常执行,这就是异常
  • golang中提供了两种处理异常的方式
    • 一种是程序发生异常时, 将异常信息反馈给使用者
    • 一种是程序发生异常时, 立刻退出终止程序继续运行

打印异常信息

  • Go语言中提供了两种创建异常信息的方式
  • 方式一: 通过fmt包中的Errorf函数创建错误信息, 然后打印
package main
import "fmt"
func main() {
    // 1.创建错误信息
    var err error = fmt.Errorf("这里是错误信息")
    // 2.打印错误信息
    fmt.Println(err) // 这里是错误信息
}
  • 方式二: 通过errors包中的New函数创建错误信息,然后打印
package main
import "fmt"
func main() {
    // 1.创建错误信息
    var err error = errors.New("这里是错误信息")
    // 2.打印错误信息
    fmt.Println(err) // 这里是错误信息
}
  • 两种创建异常信息实现原理解析
    builtin
    
package builtin
// 定义了一个名称叫做error的接口
// 接口中声明了一个叫做Error() 的方法
type error interface {
    Error() string
}
  • 在errors包中定义了一个名称叫做做errorString的结构体, 利用这个结构体实现了error接口中指定的方法
  • 并且在errors 包中还提供了一个New方法, 用于创建实现了error接口的结构体对象, 并且在创建时就会把指定的字符串传递给这个结构体
// 指定包名为errors
package errors 
// 定义了一个名称叫做errorString的结构体, 里面有一个字符串类型属性s
type errorString struct {
    s string
}
// 实现了error接口中的Error方法
// 内部直接将结构体中保存的字符串返回
func (e *errorString) Error() string {
    return e.s
}
// 定义了一个New函数, 用于创建异常信息
// 注意: New函数的返回值是一个接口类型
func New(text string) error {
        // 返回一个创建好的errorString结构体地址
    return &errorString{text}
}
  • fmt包中Errorf底层的实现原理其实就是在内部自动调用了errors包中的New函数
func Errorf(format string, a ...interface{}) error {
    return errors.New(Sprintf(format, a...))
}
  • 应用场景
package main
import "fmt"
func div(a, b int) (res int, err error) {
    if(b == 0){
        // 一旦传入的除数为0, 就会返回error信息
        err = errors.New("除数不能为0")
    }else{
        res = a / b
    }
    return
}
func main() {
    //res, err := div(10, 5)
    res, err := div(10, 0)
    if(err != nil){
        fmt.Println(err) // 除数不能为0
    }else{
        fmt.Println(res) // 2
    }
}

中断程序

  • Go语言中提供了一个叫做panic函数, 用于发生异常时终止程序继续运行
package main
import "fmt"
func div(a, b int) (res int) {
    if(b == 0){
        //一旦传入的除数为0, 程序就会终止
        panic("除数不能为0")
    }else{
        res = a / b
    }
    return
}
func main() {
    res := div(10, 0)
    fmt.Println(res)
}
  • Go语言中有两种方式可以触发panic终止程序
    • 我们自己手动调用panic函数
    • 程序内部出现问题自动触发panic函数
package main
import "fmt"
func main() {
    // 例如:数组角标越界, 就会自动触发panic
    var arr = [3]int{1, 3, 5}
    arr[5] = 666 // 报错
    fmt.Println(arr)

    // 例如:除数为0, 就会自动触发panic
    var res = 10 / 0
    fmt.Println(res)
}
  • 除非是不可恢复性、导致系统无法正常工作的错误, 否则不建议使用panic

恢复程序

  • 程序和人一样都需要具备一定的容错能力, 学会知错就改. 所以如果不是不可恢复性、导致系统无法正常工作的错误, 如果发生了panic我们需要恢复程序, 让程序继续执行,并且需要记录到底犯了什么错误
  • Go 语言中我们可以通过defer和recover来实现panic异常的捕获, 让程序继续执行
package main
import "fmt"
func div(a, b int) (res int) {
    // 定义一个延迟调用的函数, 用于捕获panic异常
    // 注意: 一定要在panic之前定义
    defer func() {
        if err := recover(); err != nil{
            res = -1
            fmt.Println(err) // 除数不能为0
        }
    }()
    if(b == 0){
        //err = errors.New("除数不能为0")
        panic("除数不能为0")
    }else{
        res = a / b
    }
    return
}

func setValue(arr []int, index int ,value int)  {
    arr[index] = value
}
func main() {
    res := div(10, 0)
    fmt.Println(res) // -1
}
  • panic注意点
    • panic异常会沿着调用堆栈向外传递, 所以也可以在外层捕获
package main
import "fmt"
func div(a, b int) (res int) {
    if(b == 0){
        //err = errors.New("除数不能为0")
        panic("除数不能为0")
    }else{
        res = a / b
    }
    return
}
func main() {
    // panic异常会沿着调用堆栈向外传递, 所以也可以在外层捕获
    defer func() {
        if err := recover(); err != nil{
            fmt.Println(err) // 除数不能为0
        }
    }()
    div(10, 0)
}
  • 多个异常,只有第一个会被捕获
package main
import "fmt"
func test1()  {
    // 多个异常,只有第一个会被捕获
    defer func() {
        if err := recover(); err != nil{
            fmt.Println(err) // 异常A
        }
    }()
    panic("异常A") // 相当于return, 后面代码不会继续执行
    panic("异常B")
}
func main() {
    test1(10, 0)
}
  • 如果有异常写在defer中, 那么只有defer中的异常会被捕获
package main
import "fmt"
func test2()  {
    // 如果有异常写在defer中, 那么只有defer中的异常会被捕获
    defer func() {
        if err := recover(); err != nil{
            fmt.Println(err) // 异常A
        }
    }()
    panic("异常A")
    defer func() { // defer会在函数执行完毕之后才会执行, 所以会在("异常A")之后执行
        panic("异常B")
    }()
}
func main() {
    test1(10, 0)
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Speed Up Your Site

Speed Up Your Site

Andrew B. King / New Riders Press / 2003-01-14 / USD 39.99

There's a time bomb on the web: user patience. It starts ticking each time someone opens one of your pages. You only have a few seconds to get compelling content onto the screen. Fail, and you can kis......一起来看看 《Speed Up Your Site》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具