脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Golang语言如何避免空指针引发的panic详解

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

2022-08-28 13:36frank Golang

简单地说go语言的指针类型和C/C++的指针类型用法是一样的,除了出去安全性的考虑,go语言增加了一些限制,这篇文章主要给大家介绍了关于Golang语言如何避免空指针引发panic的相关资料,需要的朋友可以参考下

01、介绍

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

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

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

操作返回值的字段:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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(空指针)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
}

操作返回值的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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。

?
1
2
3
4
5
6
7
8
9
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。

?
1
2
3
4
5
6
7
8
9
10
11
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。

?
1
2
3
4
5
6
7
8
9
10
11
12
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

原文链接:https://mp.weixin.qq.com/s/9s6YXJsZcXyfgWDYG-WZOQ

延伸 · 阅读

精彩推荐
  • Golanggo语言base64加密解密的方法

    go语言base64加密解密的方法

    这篇文章主要介绍了go语言base64加密解密的方法,实例分析了Go语言base64加密解密的技巧,需要的朋友可以参考下 ...

    dingding4682020-04-20
  • GolangGolang 探索对Goroutine的控制方法(详解)

    Golang 探索对Goroutine的控制方法(详解)

    下面小编就为大家分享一篇Golang 探索对Goroutine的控制方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 ...

    tr3e2312020-05-12
  • GolangGolang 语言编写 gRPC 实战项目

    Golang 语言编写 gRPC 实战项目

    本文我们介绍怎么使用 grpc 开发“分布式系统”。这里使用引号是因为分布式系统是一个大概念,本文我们先介绍使用 grpc 开发分布式系统中的 service。...

    Golang语言开发栈9232021-09-27
  • Golang一文秒懂Go 编写命令行工具的代码

    一文秒懂Go 编写命令行工具的代码

    这篇文章主要介绍了一文秒懂Go 编写命令行工具的代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    crossoverJie10862021-03-28
  • Golanggolang协程池模拟实现群发邮件功能

    golang协程池模拟实现群发邮件功能

    这篇文章主要介绍了golang协程池模拟实现群发邮件功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    陶士涵9342021-06-15
  • GolangGolang如何调用windows下的dll动态库中的函数

    Golang如何调用windows下的dll动态库中的函数

    这篇文章主要介绍了Golang如何调用windows下的dll动态库中的函数方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    uxff8022021-06-20
  • GolangGo中的nil切片和空切片区别详解

    Go中的nil切片和空切片区别详解

    这篇文章主要介绍了Go中的nil切片和空切片区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们...

    蓝色记忆12052021-04-21
  • GolangGo每日一库之quicktemplate的使用

    Go每日一库之quicktemplate的使用

    quicktemplate快速、功能强大、易于使用的Go模板引擎。比html/模板快20倍,本文我们就详细的介绍一下quicktemplate的具体使用,感兴趣的可以了解一下...

    darjun9582021-08-13