Go1.21 速览:骚操作 panic(nil) 将成为历史!以后别这么干了。。。

news/2024/7/16 8:31:49 标签: xcode, macos, ide

大家好,我是煎鱼。

在 Go 语言中,返回错误、抛出异常一直是大家比较关注的话题。在抛出异常上,我们一般都是这么用的:

func mayPanic() {
    panic("脑子进煎鱼了")
}

func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered. Error:\n", r)
            return
        }
        
        fmt.Println("煎鱼进脑子了")
    }()

    mayPanic()

    fmt.Println("After mayPanic()")
}

运行结果:

Recovered. Error:
 脑子进煎鱼了

这看起来一切正常,没什么问题的样子。

隐晦的雷

其实在现在的 Go 版本有一个较隐晦的雷。看看 panic 和 recover 对应的参数和返回类型。如下:

func panic(v interface{})
func recover() interface{}

参数值类型是 interface,也就意味着可以传任何值。那我们传 nil 给 panic 行不行呢?

如下代码:

func mayPanic() {
 panic(nil)
}

func main() {
 defer func() {
  if r := recover(); r != nil {
   fmt.Println("Recovered. Error:\n", r)
   return
  }

  fmt.Println("煎鱼进脑子了")
 }()

 mayPanic()

 fmt.Println("After mayPanic()")
}

再看一下输出结果,你认为是什么?

运行结果:煎鱼进脑子了。

虽然确实调用 panic(nil) 往里传了 nil 值。这结果说对好像也对,说不对好像也很怪?

因为我们触发了异常(panic),就是希望程序抛出异常,但却因为入参 “阴差阳错” 是 nil,这个应用程序就按正常逻辑走的。这显然和 panic 的语法特性预期不相符。

甚至社区有反馈,因为这一个坑,他们团队花了 3 个小时来排查:

91bf971b4e85e3e87eb3e14a1597bd30.png

还是有些隐晦的,不遇到的还真不一定知道。

修复 panic(nil)

这在 2018 年由 Go 的核心成员@ Brad Fitzpatrick 提出了《spec: guarantee non-nil return value from recover[1]》期望得到解决。

如下图:

75b281732a4fd31807e2be89fffe08cb.png

其认为 panic(nil) 现在的处理是不正确的,应该要返回 runtime 错误,类似 runtime.NilPanic 的一个特殊类型。

经过 4-5 年的社区讨论、放置、纠结、处理后,将会在 Go1.21 起正式提供一个 PanicNilError 的新错误类型,用于替换和修复 panic(nil) 的场景。

PanicNilError 类型定义如下:

// A PanicNilError happens when code calls panic(nil).
//
// Before Go 1.21, programs that called panic(nil) observed recover returning nil.
// Starting in Go 1.21, programs that call panic(nil) observe recover returning a *PanicNilError.
// Programs can change back to the old behavior by setting GODEBUG=panicnil=1.
type PanicNilError struct {
 // This field makes PanicNilError structurally different from
 // any other struct in this package, and the _ makes it different
 // from any struct in other packages too.
 // This avoids any accidental conversions being possible
 // between this struct and some other struct sharing the same fields,
 // like happened in go.dev/issue/56603.
 _ [0]*PanicNilError
}

func (*PanicNilError) Error() string { return "panic called with nil argument" }
func (*PanicNilError) RuntimeError() {}

在新版本中,Go 应用程序调用 panic(nil) 将会在 Go 编译器中被替换成 panic(new(runtime.PanicNilError)),这一动作变更 Go1.20 及以前的行为。

在 Go1.21 起,调用 panic(nil) 的运行结果会变成:

panicked: panic called with nil argument

由于这一行为本身是破坏 Go1 兼容性保障的,因此 Go 团队提供了兼容措施,在 Go 编译时新增 GODEBUG=panicnil=1 标识,就可以确保与老版本行为一致。

总结

在 Go 语言中,panic 关键字本身的目标就是抛出异常,但早期设计上出现了一定的纰漏,使用 nil 可以让应用程序继续正常运行。

这也算一个比较常见的点了,和平时写业务代码一样。要确保边界值和特殊值的判断,这样才能确保代码的健壮性和异常处理与预期保持一致。

推荐阅读

  • 写在 2023 年初的后端社招面试经历(四年经验):字节 米哈游 富途 猿辅导

  • Go 的一些有趣数据:中国最多人用、开发者年轻;PHP 明显下滑的趋势

  • 快速上手 Go CGO,掌握在 Go 里写 C!

参考资料

[1]

spec: guarantee non-nil return value from recover: https://github.com/golang/go/issues/25448

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

78eda70a0dc604a20baf5a9a633f23c5.jpeg

4b59cdcdc319cb58b506db143119e1f4.png

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!


http://www.niftyadmin.cn/n/382337.html

相关文章

深入解析Spring源码系列:Day 7 - Spring事务管理原理

深入解析Spring源码系列:Day 7 - Spring事务管理原理 欢迎来到本系列的第七篇博客。在之前的博客中,我们已经深入了解了Spring框架的核心概念和一些重要组件的工作原理。今天,我们将探索Spring框架中的事务管理机制。 Spring事务管理概述 …

基于django的物流管理系统

摘要 随着全球经济的蓬勃发展,WTO的成立也给全球的商业活动带来了新的挑战,因此,企业需要充分发挥自身的优势,运用最新的科学技术,在互联网、信息科学的指导下,完善现有的管理体系,实现全面的创…

Conda:管理Python环境从未如此简便

本文主要介绍miniconda在linux平台的安装,windows平台只会更加便捷。 安装 在清华源上下载对应服务器版本的Miniconda3,在此下载的是Linux的最新版本的Miniconda3. 下载conda安装包 wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/M…

基于PP-OCRv3的车牌检测和识别

本项目基于百度飞桨AI Studio平台进行实现,百度出品的深度学习平台飞桨(PaddlePaddle)是主流深度学习框架中一款完全国产化的产品,与Google TensorFlow、Facebook Pytorch齐名。2016 年飞桨正式开源,是国内首个全面开源…

界面控件DevExpress ASP.NET新主题——Office 365暗黑主题的应用

DevExpress ASP.NET Web Forms Controls拥有针对Web表单(包括报表)的110种UI控件,DevExpress ASP.NET MVC Extensions是服务器端MVC扩展或客户端控件,由轻量级JavaScript小部件提供支持的70个高性能DevExpress ASP.NET Core Contr…

解决win11家庭版安装Ubuntu问题

参考:Windows系统上的Ubuntu wsl使用以及wsl连接远程服务器指南 - 知乎 前提,已经启用虚拟机,并已安装Hyper-V 1、使用脚本安装Ubuntu容易报错,可以使用MicrosoftStore进行安装,如果下载报错,检查虚拟机是…

领导说培养我,怎么看出来他是真培养,还是PUA我?

当你的领导说要培养你的时候,如何分辨他的真实意图? 一位网友问: 领导说培养我,怎么看出来他是真培养,还是PUA? 来看看这位网友的支招: 如果领导做到以下几点,那就是真的培养你。 1.…

【Python】Python系列教程--Python3 环境搭建(二)

文章目录 前言Python3 下载Python 安装Unix & Linux 平台安装 Python3:Window 平台安装 Python:MAC 平台安装 Python: 环境变量配置在 Unix/Linux 设置环境变量在 Windows 设置环境变量在命令提示框中(cmd) : 输入 Python 环境变量运行 Python1、交互式解释器:2…