- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
Golang 没有结构化异常,使用 panic 抛出错误,recover 捕获错误.
panic、recover 参数类型为 interface{},因此可抛出任何类型对象.
func panic(v interface{})
func recover() interface{}
处理流程:方法体重抛出一个 panic 的异常,然后在 defer 中通过 recover 捕获这个异常,然后正常处理.
关于 panic:
触发运行时错误:panic 用于立即停止当前函数的执行,并开始回溯调用栈直到程序终止或遇到 recover。 传递错误信息:panic 可以接受任何类型的参数,通常传递字符串或错误接口实例,方便错误信息的传递和处理。 易错点:随意使用 panic 处理非严重错误是不推荐的,其主要用于处理不可恢复的运行时错误,对于可处理的错误,应通过返回错误值的方式传递给调用者.
关于 recover:
捕获 panic:recover 只能在 defer 语句中调用,用于捕获当前 goroutine 发生的 panic,如果没有 panic 发生,则返回 nil。 recover 处理异常后:逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点。 易错点:recover 只能捕获同一 goroutine 内发生的 panic,对于其他 goroutine 引发的 panic 无能为力.
Go 语言推荐使用错误返回码而非异常机制来处理错误,通过 error 接口返回错误信息,这是一种更灵活且不会破坏程序执行流程的方法。在实际开发中,建议优先使用错误处理机制,谨慎使用 panic 和 recover,以编写出更加稳定和高效的 Go 程序.
如下代码,直接触发 panic,在 defer 中通过 recover 捕获,并转换成 string 输出:
package main
func main() {
test()
}
func test() {
defer func() {
if err := recover(); err != nil {
println("输出:", err.(string)) // 将 interface{} 转型为具体类型 string
// 输出: panic error!
}
}()
panic("panic error!")
}
再来个示例,往已关闭的通道中发送数据,会引发异常:
package main
import (
"fmt"
)
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err) // 输出:send on closed channel
}
}()
var ch chan int = make(chan int, 10)
close(ch) // 关闭通道
ch <- 1 // 继续往通道中发送值,就会引发异常
}
延迟调用中引发的错误,可被后续延迟调用捕获,但仅最后一个错误可被捕获.
如下代码,只有 defer 中的 panic 会被捕获,另一个异常将会漏掉:
package main
import "fmt"
func test() {
defer func() {
fmt.Println(recover())
}()
defer func() {
panic("defer panic")
}()
panic("test panic")
}
func main() {
test()
}
// 输出:
// defer panic
因此,需要再第二个 defer 中针对 test panic 进行处理.
捕获函数 recover 只有在延迟调用内直接调用才会终止错误,否则总是返回 nil。任何未捕获的错误都会沿调用堆栈向外传递.
如下代码,在第一层进行了延迟调用,然后第〇层就未获取到 panic:
package main
import "fmt"
func test() {
defer func() {
fmt.Println("第〇层:", recover()) // 无效
}()
defer func() {
fmt.Println("第一层:", recover()) // 有效
}()
defer fmt.Println("第二层:", recover()) // 无效!
defer fmt.Println("第三层:", recover()) // 无效!
defer func() {
func() {
println("第四层:defer inner")
fmt.Println("第四层:", recover()) // 无效!
}()
}()
panic("test panic")
}
func main() {
test()
}
// 输出:
// 第四层:defer inner
// 第四层: <nil>
// 第三层: <nil>
// 第二层: <nil>
// 第一层: test panic
// 第〇层: <nil>
除用 panic 引发中断性错误外,还可返回 error 类型错误对象来表示函数调用状态.
type error interface {
Error() string
}
标准库 errors.New 和 fmt.Errorf 函数用于创建实现 error 接口的错误对象。通过判断错误对象实例来确定具体错误类型.
package main
import (
"errors"
"fmt"
)
var ErrDivByZero = errors.New("division by zero") // 定义错误类型 ErrDivByZero
func div(x, y int) (int, error) {
if y == 0 {
return 0, ErrDivByZero
}
return x / y, nil
}
func main() {
defer func() {
fmt.Println(recover()) // 捕获 panic,无 panic 就打印 <nil>
}()
switch z, err := div(10, 0); err { // div(10, 0) 返回 ErrDivByZero
case nil:
println(z)
case ErrDivByZero: // 触发 panic
panic(err)
}
}
// 输出:
// division by zero
将代码块重构成匿名函数,并包含异常处理,如此可确保后续代码被执行.
如下代码,当被除数为 0 时会报错,在匿名函数中被捕获并记录,然后不影响正常输出:
package main
import "fmt"
func test(x, y int) {
var z int
func() {
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
z = 0
}
}()
z = x / y
}()
fmt.Printf("x / y = %d\n", z)
}
func main() {
test(2, 0)
}
// 输出:
// err: runtime error: integer divide by zero
// x / y = 0
package main
import "fmt"
func Try(fun func(), handler func(interface{})) {
defer func() {
if err := recover(); err != nil {
handler(err) // 捕获异常后,执行异常处理逻辑
}
}()
fun() // 直接执行处理逻辑
}
func main() {
Try(
func() {
// 程序处理逻辑。。。
panic("test panic") // 抛出异常
},
func(err interface{}) {
// 异常处理逻辑。。。
fmt.Println(err)
},
)
}
参考:http://www.topgoer.com/%E5%87%BD%E6%95%B0/%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86.html 。
最后此篇关于Go语言中的异常处理简单实践panic、recover【GO基础】的文章就讲到这里了,如果你想了解更多关于Go语言中的异常处理简单实践panic、recover【GO基础】的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在Go(go1.2.1 linux/amd64)中运行http服务器时,我遇到了一个罕见的错误。 unexpected fault address 0xb84004 fatal error: faul
使用以下代码: var i interface{} = "hello" f, ok := i.(float64) fmt.Println(f, ok) f = i.(float64) // panic
考虑以下故意导致双重 panic 的代码: use scopeguard::defer; // 1.1.0 fn main() { defer!{ panic!() }; defer!
如果我传递给 std::panic::set_hook 的函数发生 panic 会怎样? 我可以想象对此做出多种 react :考虑这个 UB,中止程序 like C++ does ,为新的 pani
我有一个 string,当我想获取 i 索引处的值时它会崩溃,但是当我切出相同的 string 保持较低的索引值作为长度然后它不会 panic 。想知道 1 和 2 有何不同? func main()
看起来不可能从 panic 中的 panic 中恢复过来? func TestError(t *testing.T) { e := &myErr{p: false} fmt.Print
当我使用 cargo test 运行以下程序时: use std::panic; fn assert_panic_func(f: fn() -> (), msg: String) { let
在开发过程中,我遇到了崩溃,并显示了内核 panic 上传模式。 有没有办法以某种方式连接到设备并提取日志? 最佳答案 我希望这就是您正在寻找的...来源:StackOverflowAndroid 创
我需要制造内核 panic ,我尝试了以下操作 sysctl kernel.panic=0 && echo c > /proc/sysrq-trigger 当我运行上面的命令时。我看到系统总是重新启动
是否可以从 recover 中“重新抛出”错误并保留原始堆栈跟踪?我知道的最好的办法就是再次 panic ,但这确实会创建一个新的堆栈跟踪。 func do() { defer func()
我正在使用 panic::catch_unwind引起 panic : use std::panic; fn main() { let result = panic::catch_unwind
func sub(){ defer func (){ panic(2) }() panic(1) } func main(){ defer func()
考虑到我使用的是原始的“errors”go 包。 还有,panic(11) 和 panic("11") 之间的区别? 最佳答案 panic定义为 func panic(v interface{}),调
我是 golang 的新手。在定义位置后 try catch 主 block 中的错误后,我的程序出现 panic 。我在某处读过,添加 defer.close() 可能会有所帮助,但编译器再次说你的
有这种新的编程语言 V-lang由亚历克斯·梅德维尼科夫 (Alex Medvednikov) 创建。我目前使用的是 V-lang 0.1.11 版。我可以在 V-lang 中声明一个数组,如下所示:
在启动 linux 时,我在控制台上得到以下打印,并且系统挂起。 Waiting for root device /dev/mmcblk0p2... mmc_host mmc0: Bus speed
我已经实现了这个 answer 中提到的 goroutine 的生产者-消费者模式.但它有时会出现 panic ,并出现错误提示:“ panic :同步:负 WaitGroup 计数器”。我有如下示例
上下文: https://github.com/fusspawn/tserver/blob/master/app/controllers/gorp.go 作为尝试设置 gorm 的一部分,我尝试转换标
专注Golang,Python语言,云原生,人工智能领域得博主 过去经历的意义在于引导你,而非定义你, 只要我们足够努力,任何人都有无限潜力 panic 抛出异常函数 recove
这个问题在这里已经有了答案: How to return a value in a Go function that panics? (3 个回答) 2年前关闭。 package main impor
我是一名优秀的程序员,十分优秀!