乘风原创程序

  • Golang语言如何避免空指针引发的panic详解
  • 2022/1/6 15:34:59
  • 01、介绍

    在 golang 语言项目开发中,变量操作不当就会触发空指针引发程序 panic。空指针就是未分配内存的指针类型的变量,变量的值是 nil,因为操作空指针会引发 panic,所以我们在程序开发中要特别小心。

    02、结构体指针类型返回值

    在调用结构体指针类型返回值的函数或方法时,并且需要操作返回值的字段或方法,此时,我们就需要注意触发空指针引发的 panic。

    操作返回值的字段:

    func main() {
    ?user := getuser()
    ?fmt.println(user)
    ?fmt.println(user.id)
    }
    
    func getuser() (user *user) {
    ?return
    }
    
    type user struct {
    ?id ? int
    ?name string
    }

    阅读上面这段代码,我们通过调用函数 getuser() 获取 *user 类型的返回值,因为返回值变量是空指针,当我们访问返回值的字段时,程序引发 panic。

    避免此类空指针问题,一是可以在返回值包含指针类型变量的函数或方法中,在函数体开头初始化返回值的指针类型变量;二是在调用结构体指针类型返回值的函数或方法时,在操作返回值的字段或方法时,先判定返回值是否为 nil(空指针)。

    func main() {
    ?user := getuser()
    ?fmt.println(user)
    ?if user != nil {
    ? fmt.println(user.id)
    ?}
    }
    
    func getuser() (user *user) {
    ?user = new(user)
    ?// user = &user{}
    ?return
    }
    
    type user struct {
    ?id ? int
    ?name string
    }

    操作返回值的方法:

    func main() {
    ?user := getuser()
    ?user.login()
    }
    
    func getuser() (user *user) {
    ?return
    }
    
    type user struct {
    ?id ? int
    ?name string
    }
    
    func (u user) login() {
    
    }

    阅读上面这段代码,我们通过调用函数 getuser() 获取 *user 类型的返回值,因为返回值变量是空指针,当我们访问返回值的方法 login() 时,程序触发空指针引发 panic。

    避免此类空指针问题,一是可以在返回值是指针类型变量的函数或方法的函数体中,开头先初始化返回值的指针类型变量;二是类型方法的接收者使用指针类型。

    func main() {
    ?user := getuser()
    ?user.login()
    }
    
    func getuser() (user *user) {
    ?user = new(user)
    ?// user = &user{}
    ?return
    }
    
    type user struct {
    ?id ? int
    ?name string
    }
    
    func (u *user) login() {
    
    }

    03、结构体指针类型 value 的 map

    在 golang 语言程序开发中,经常会操作结构体指针类型 value 的 map,也需要注意触发空指针引发 panic。

    func main() {
    ?var userdata map[int]*user
    ?fmt.println(userdata[1].name)
    }
    
    type user struct {
    ?id ? int
    ?name string
    }

    阅读上面这段代码,我们定义 map 类型的变量 userdata,key 是 int 类型,value 是结构体指针类型,我们访问 map 的值时,因为值是空指针,所以会引发 panic。

    避免此类空指针问题,我们可以使用 ok-idiom 模式判断键值是否存在,如果键值存在(判断键值是否为 nil),我们访问键值的字段,否则不访问。通过这种方式,也可以避免触发空指针引发 panic。

    func main() {
    ?var userdata map[int]*user
    ?if val, ok := userdata[1]; ok {
    ? fmt.println(val.name)
    ?}
    }
    
    type user struct {
    ?id ? int
    ?name string
    }

    04、defer 延迟调用

    关键字 defer 延迟调用函数,虽然被调用函数会延迟调用,但是被调用函数的变量会先被注册。所以,如果被调用函数的变量是空指针,就会引发 panic。

    func main() {
    ?res, err := http.get("http://www.baidu2022.com/robots.txt") // 伪造错误请求
    ?defer res.body.close()
    ?if err != nil {
    ? log.fatal(err)
    ?}
    ?body, err := io.readall(res.body)
    ?if err != nil {
    ? log.fatal(err)
    ?}
    ?fmt.printf("%s", body)
    }

    阅读上面这段代码,使用 defer 延迟调用函数释放资源,因为我们将 defer 放在错误检查之后,所以如果返回值 res 是空指针,就会引发 panic。

    避免此类空指针问题,我们可以在使用 defer 调用之前,先做错误检查,并且遇到错误后停止向下执行。

    05、总结

    本文我们介绍一些 golang 语言开发需要避免空指针引发 panic 的场景,虽然都比较简单,但是新手很容易踩“坑”。

    到此这篇关于golang语言如何避免空指针引发panic的文章就介绍到这了,更多相关go语言避免空指针引发panic内容请搜索本教程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持本教程网!

    参考资料:

    • https://yourbasic.org/golang/gotcha-nil-pointer-dereference/
    • https://blog.wuhsun.com/panic-runtime-error-invalid-memory-address-or-nil-pointer-dereference/
    • https://programmerah.com/go-solve-panic-runtime-error-invalid-memory-address-or-nil-pointer-dereference-in-golang-28179/
    • https://stackoverflow.com/questions/16280176/go-panic-runtime-error-invalid-memory-address-or-nil-pointer-dereference