异常
异常
网上有吐槽 Go 的异常处理不是很好,原因暂时不知
异常的处理主要使用:
- 内置 
- defer
 - recover
 
 - errors包 
- errors.New
 - errors.panic
 
 
异常
package main
import "fmt"
func main() {
    div(10, 5)		// 能执行成功
    div(10, 0)		// 会报错:panic: runtime error: integer divide by zero
}
func div(num1 int, num2 int) {
    result := num1 / num2
    fmt.Println(result)
}异常类型
- 特别需要注意:Go有一种异常为 “panic”,翻译过来叫 “恐慌”,有点怪怪的。这种异常可以通过 recover 恢复(类似其他语言的try-catch)
 
defer + recover 机制处理错误
defer 基本用法 (在函数中)
与其他语言不同:Go特有。
不同语言的类似处理:
goto方法
- 略
 
C语言
Setjmp/Longjmp
可以用来实现异常处理和资源释放。setjmp用于捕获当前环境的上下文,而longjmp则用于从setjmp返回,并可以选择性地执行资源释放代码。
这种方法可以在异常发生时跳转到函数的末尾执行清理代码,而不需要使用大量的if语句。
C++
RAII (Resource Acquisition Is Initialization)
与智能指针(如std
shared_ptr)一起使用。当对象被创建时,它会获取资源;当对象被销毁时,它会自动释放资源。 
Java的 try-with-resources/try-catch-finally
FileWriter writer = null; try { writer = new FileWriter("example.txt"); // 使用writer对象 // ... } catch (IOException e) { // 处理异常 // ... } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { // 处理关闭资源时的异常 // ... } } }Python
上下文管理器
__exit__、__enter__、with__exit__方法定义了退出with语句块时的行为,通常用于释放资源class MyResource: def __enter__(self): # 获取资源 return self def __exit__(self, exc_type, exc_value, traceback): # 释放资源 if exc_type: # 如果有异常发生,可以选择处理或忽略 print(f"An exception occurred: {exc_type}, {exc_value}") # 总是执行资源释放 # ... with MyResource() as resource: # 使用资源 # ... # 上面是自己定义的情况。一般用得比较多的是打开文件的 open with,无需显式调用 close() 方法C#
- using语句,类似于Java的try-with-resources
 
JavaScript
- Promise和async/await
 
Go语言
- 函数内处理异常:Go使用defer关键字用于处理函数的资源释放,以及异常处理等(关于defer的更多信息,详见Go语言的 “异常” 部分)
Go 追求代码优雅,不使用 try-catch 机制,而是使用 defer+recover 机制- defer关键字:可以在函数返回前执行一段代码,通常用于资源释放。
 - recover关键字:允许程序管理恐慌过程。recover() 可以捕获异常,同时使程序恢复正常,停止恐慌过程
 - 结合 try-defer 模式,可以在发生异常时自动释放资源,而无需在每个判断点重复编写释放代码
 
 - 函数外处理异常:不使用 “抛出” 异常,由于Go可以多返回值,只需要 “返回” 异常即可
 
- 函数内处理异常:Go使用defer关键字用于处理函数的资源释放,以及异常处理等(关于defer的更多信息,详见Go语言的 “异常” 部分)
 
recover
内置函数 recover
作用:允许程序管理恐慌过程。recover() 可以捕获异常,同时使程序恢复正常,停止恐慌过程
defer + recover 处理异常
package main
import "fmt"
func main() {
    div(10, 5)		// 能执行成功
    div(10, 0)		// 会报错:panic: runtime error: integer divide by zero
}
func div(num1 int, num2 int) {
    // defer+recover 捕获错误
    defer func() {			// 这里是一个匿名的立刻执行函数
        err := recover()	// 如果没有捕获错误,返回值为零值:nil
        if err != nil {
            fmt.Println("错误捕获了, 异常为:", err)
        }
    }()
    result := num1 / num2
    fmt.Println(result)
}异常处理和错误处理
看课看到异常部分时有个弹幕:大哥你这是异常处理不是错误处理,error和panic都没搞清楚。于是我搜了下
- 其他语言:异常处理是通过 
try-catch-finally这样的结构来实现的。例如,在Java或C#中,你可以使用这些关键字来捕获和处理异常 - Go语言:在某些编程语言中,特别是Go语言,
error和panic是两种不同的机制,用于处理不同类型的问题- error:是一个接口类型,用于表示错误情况。当函数执行失败时,它通常会返回一个
error对象,调用者可以检查这个对象来确定是否发生了错误,并获取错误的详细信息 - panic:是一个内置函数,用于在发生严重错误时终止程序的执行。这通常用于那些不应该发生的情况,比如内部一致性被破坏、严重的逻辑错误等。当
panic被调用时,当前的函数会立即停止执行,跳转到最近的defer语句(如果有的话),然后程序会打印堆栈跟踪信息并退出。 
 - error:是一个接口类型,用于表示错误情况。当函数执行失败时,它通常会返回一个
 
自定义错误 errors包.New()
不同与其他语言:由于Go有多返回值的特性,并不需要像其他语言那样 “抛出” 异常,而仅需 “返回” 异常。这点不错
package main
import (
    "fmt"
    "errors"
)
func main() {
    err := div(10, 5)
    if err != nil {
        fmt.Println("自定义错误: ", err)
    }
    err = div(10, 0)
    if err != nil {
        fmt.Println("自定义错误: ", err)
    }
}
func div(num1 int, num2 int) (err error) { 
    if num2 == 0 {
        // 抛出自定义异常
        return errors.New("除数不能为0")
    } else {
        result := num1 / num2
        fmt.Println(result)
        return nil
    }
}终止程序 errors.panic
有时程序出现错误时,应该立即终止
func panic(v interface{})
// 使用
err := test()
if err != nil {
    fmt.Println("自定义错误: ", err)
    panic(err)
}链接到当前文件 0
没有文件链接到当前文件