Golang语言如何避免空指针引发的panic详解

作者:frank 时间:2024-05-29 22:07: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 的场景,虽然都比较简单,但是新手很容易踩“坑”。

参考资料:

  • 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

来源:https://mp.weixin.qq.com/s/9s6YXJsZcXyfgWDYG-WZOQ

标签:go语言,空指针,panic
0
投稿

猜你喜欢

  • 用python实现PDF解密打印文件

    2022-01-01 03:53:44
  • Yahoo!网站性能最佳体验的34条黄金守则——图片、Coockie与移动应用

    2008-05-29 13:44:00
  • Python tempfile模块学习笔记(临时文件)

    2022-05-27 02:32:08
  • python socket网络编程之粘包问题详解

    2023-10-13 17:40:10
  • Python基于回溯法子集树模板解决m着色问题示例

    2023-11-14 12:22:59
  • 对Python实现简单的API接口实例讲解

    2023-11-20 03:27:04
  • 详解Tensorflow数据读取有三种方式(next_batch)

    2023-08-10 07:30:42
  • windows 2000 IIS下配置Php+Mysql+zend的图文教程(完整版)

    2007-06-15 10:51:00
  • python matplotlib中的subplot函数使用详解

    2021-02-18 00:00:28
  • Python 弹窗设计小人发射爱心

    2021-07-16 14:41:01
  • 使用ASP调用C#写的COM组件

    2010-04-03 20:45:00
  • MySQL数据库学习之排序与单行处理函数详解

    2024-01-22 13:01:01
  • Oracle 常用的SQL语句

    2009-08-02 07:09:00
  • pandas如何删除没有列名的列浅析

    2021-05-17 11:08:47
  • JavaScript利用Canvas实现粒子动画倒计时

    2024-04-16 09:37:52
  • 10分钟用Python快速搭建全文搜索引擎详解流程

    2023-11-06 16:13:41
  • 浅谈Django中view对数据库的调用方法

    2024-01-17 02:13:28
  • Python数据结构之链表详解

    2023-07-21 04:16:19
  • php替换字符串中间字符为省略号的方法

    2023-09-30 20:16:04
  • PHP实现按之字形顺序打印二叉树的方法

    2023-07-05 08:33:30
  • asp之家 网络编程 m.aspxhome.com