• 吾爱摆渡-资源分享平台
ad
ad
ad

Home / 知识教程 / [golang]91、Golang 语言怎么避免引发 panic?

[golang]91、Golang 语言怎么避免引发 panic?

2022-01-06 16:42:00
122 阅读

01 介绍

在 Golang 语言中,程序引发 panic 会导致程序崩溃,所以我们在程序开发时,需要特别小心,避免引发 panic。本文我们介绍 Golang 语言中比较容易引发 panic 的操作。


02 指针

任意一种编程语言都会使用函数,我们使用 Golang 编写函数或方法时,经常会用到指针类型的返回值,这时如果执行调用空指针(指针未初始化或值为 nil),对于新手而言,就很容易引发程序 panic。

type User struct {
 Name string
 Age  int
}

func (u *User) GetInfo() (data *User) {
 data = &User{
  Name: "frank",
  Age:  18,
 }
 return data
}

func main() {
 user := new(User)
 userInfo := user.GetInfo()
 fmt.Println(userInfo)
 if userInfo.Age >= 18 {
  fmt.Println("this is a man")
 }
}

我们阅读上面这段代码,这是一段非常简单的返回值为指针类型的示例代码,读者朋友们试想一下。

如果 GetInfo 方法体中的 data 的值来源于调用另外一个函数或方法,被调用的这个函数或方法返回值是 nil,而我们 main 函数中会使用返回值的 Age 字段作为判定条件,这时程序就会引发 panic,导致程序崩溃。

所以,我们在使用指针类型时,要特别小心,不然我们就只能在调用函数或方法之前,使用 defer 和 recover 添加一段补偿代码,我个人感觉不是很优雅。

defer func() {
  if err := recover(); err != nil {
   fmt.Println("err = ", err)
  }
 }()

我一般是在判定指针类型的返回值时,为了避免程序引发 panic,我会加一个且(&&)的判定条件,判定返回值不是 nil,并且返回值的某个字段符合某种条件。

func main() {
 ...
  
 if userInfo != nil && userInfo.Age >= 18 {
  fmt.Println("this is a man")
 }
}


03 数组和切片

数组和切片类型,当我们越界访问时,也会引发 panic,导致程序崩溃。不过,一般 IDE 可以提示数组越界访问的错误,如果读者朋友使用的编辑器不会提示数组越界的错误,那你使用数组也要小心了。

func main() {
 code := []string{"php", "golang"}
 fmt.Printf("len:%d cap:%d val:%s \n", len(code), cap(code), code)
 fmt.Println(code[2])
}


04 通道

如果我们关闭未初始化的通道,重复关闭通道,向已经关闭的通道中发送数据,这三种情况也会引发 panic,导致程序崩溃。

func main() {
 var ch chan int
 // close(ch)
 ch = make(chan int, 1)
 ch <- 1
 // close(ch)
 // close(ch)
 ch <- 2
}


05 映射

如果我们直接操作未初始化的映射(map),也会引发 panic,导致程序崩溃。

func main() {
 var m map[string]int
 // m = make(map[string]int)
 m["php"] = 80
}

另外,操作映射可能会遇到的更为严重的一个问题是,同时对同一个映射并发读写,它会触发 runtime.throw,不像 panic 可以使用 recover 捕获。所以,我们在对同一个映射并发读写时,一定要使用锁。

func main() {
 var m map[string]int
 m = make(map[string]int)
 go func(map[string]int) {
  for {
   m["php"] = 80
  }
 }(m)

 go func(map[string]int) {
  for {
   _ = m["php"]
  }
 }(m)

 time.Sleep(time.Second)
}

输出结果:

fatal error: concurrent map read and map write

goroutine 7 [running]:
runtime.throw({0x10a7510, 0x0})
        /usr/local/opt/go/libexec/src/runtime/panic.go:1198 +0x71 fp=0xc000050f28 sp=0xc000050ef8 pc=0x102fa51


06 类型断言

如果类型断言使用不当,比如我们不接收布尔值的话,类型断言失败也会引发 panic,导致程序崩溃。

func main() {
 var name interface{} = "frank"
 // a, ok := name.(int)
 // fmt.Println(a, ok)
 a := name.(int)
 fmt.Println(a)
}


07 总结

本文我们介绍 Golang 语言中容易引发 panic 的场景,尤其是空指针操作是最容易踩坑的场景,我们在程序开发中,一定要小心使用指针类型。

读者朋友们在程序开发中,还遇到过哪些场景引发 panic,欢迎在留言区和大家分享。



我要发布信息 | 求资源 | 解压密码 | 交流群 | 吾爱摆渡
img
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。 本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。 如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
标签
author
吾爱摆渡

站长

评论
登录后评论