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


猜你喜欢
- Python list在介绍 Python tuple 时,我使用了类比的方法,将其比做一个袋子,您可以在袋子中存放不同的东西。Python
- JAVA程序想要访问数据库,需要进行如下准备:1.安装一个数据库(这里使用mysql免安装版)2.下载该数据库的驱动包(这里使用mysql官
- 前言:我们想要在爬虫中使用xpath、beautifulsoup、正则表达式,css选择器等来提取想要的数据,但是因为scrapy是一个比较
- 例如,有一个字典如下:>>> dic = {"name": "botoo",&qu
- 滑动拼图验证码可以算是滑块验证码的进阶版本,其验证机制相对复杂。本节将介绍两种滑动拼图验证码:初级版和高级版本。初级版滑块拼图验证码初级版滑
- 缩略图在很多时候我们都需要将图片按照同比例缩小有利于存储 但是一张张手动去改的话太麻烦了 今天我们就用python实现一个简单的将一个文件夹
- 1. 问题描述水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数,水仙花数是指一个3位数,它的每个位上的数字的3次幂
- 前言本文主要给大家分享了一些简单的Python练习题,对学习python的新手们来说是个不错的练习问题,下面话不多说了,来一起看看详细的介绍
- Sublime Text 3非常实用,但是想要用好,一些快捷键不可或缺,所以转了这个快捷键汇总。用惯了vim,有些快捷键也懒得用了,尤其是在
- 前言:数据库的操作越来越成为整个应用的性能瓶颈了,这点对于 Web 应用尤其明显。关于数据库的性能,这并不只是 DBA 才需要担心的事,而这
- #!/usr/bin/env python# -*- coding:utf-8-*-# file: {NAME}.py# @author:
- 卸载MySQL1、在控制面板,卸载MySQL的所有组件控制面板——》所有控制面板项——》程序和功能,卸载所有和MySQL有关的程序2、找到你
- File System的缩写是fs,该模块提供本地文件的读写能力。Nodejs导入文件系统模块(fs)语法如下所示:var fs = req
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML&nb
- 工作中最常见的配置文件有四种:普通key=value的配置文件、Json格式的配置文件、HTML格式的配置文件以及YMAML配置文件。这其中
- 一、序言前段时间一直在弄报表,快被这些报表整吐了,然后接触到了Oracle的table()函数。所以今天把table()函数的具体用法整理下
- 自定义组件挂载原型上以elementUI二次分装dialog举例PageDialog.vue<!-- 页面提示弹框 --><
- yaml文件内容apiVersion: policy/v1beta1kind: PodSecurityPolicymetadata: &nb
- 🌌 专注Golang,Python语言,云原生,人工智能领域得博主💜 过去经历的意义在于引导你,而非定义你,💜 只要我们足够努力,任何人都有
- 通过变量ID得到变量的值已知获得变量的id用函数id(),那么它的反函数是什么?答案是:PyObj_FromPtr,据此,写了一个函数di(