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

news2024/11/26 8:53:41

大家好,我是煎鱼。

在 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.coloradmin.cn/o/595992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vagrant编排虚拟机安装与配置

1.安装VirtualBox与Vagrant VirtualBox与Vagrant是支持不通过操作系统的;根据具体操作系统下载对应版本即可。(这里使用windows操作系统搭建) VirtualBox https://www.virtualbox.org/wiki/Downloads Vagrant https://developer.hashicorp.com/vagrant/downloads Va…

设计模式之~状态模式

状态模式(State),当一个对象的内部状态改变时允许改变其行为,这个对象看起来像是改变了其类。 能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这些 可能发生的外部情况全部考虑到&#xff…

基于html+css的图展示102

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

应用运维的三个项目

应用运维 目录概述需求: 设计思路实现思路分析1.开发和运维2.比重3.历史项目4.工作内容5.历程 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,…

程序员的新出路:维护老项目?

1 张大胖刚进入公司,遇到了一个神奇的同事:何小痩。 别人工作都很忙, 何小痩工作似乎特别轻松,从来不加班,到点儿就回家。 张大胖向别人一打听,原来何小痩一直在维护一个老项目,维护了5年了。 …

「小产品独立变现实战训练营1期」门票限时优惠

大家好,我是凯凯刘,一名程序员,一直在做小产品的开发变现,目标就是让小产品的变现更简单。【小产品独立变现实战训练营1期】这个课程主要是围绕着如何开发出一个赚钱小产品这个主题。来跟大家一起从0开始实战,一步步跟…

为什么对象存储深度归档价格低?

AWS(亚马逊云服务)对象存储S3(Simple Storage Service)有以下四种不同的存储类型: S3 标准存储: 这是最常用的S3存储类型之一,它保证了高持久性,并提供 99.999999999% 的数据耐久性…

chatgpt赋能python:Python人脸识别:从入门到工程实践

Python人脸识别:从入门到工程实践 介绍 近年来,人脸识别技术越来越成熟,广泛应用于各行各业,如社交媒体、安防、金融等领域。Python人脸识别作为一种基于机器学习的技术,可以通过训练模型从图像中自动识别出人脸,并进…

致敬六一,用外观模式实现一个儿童乐园畅玩平台

一、概述 外观模式(Facade Pattern)是一种结构型设计模式,它为多个子系统中的操作提供一个统一的高层接口,用于访问复杂子系统的功能。其核心思想是通过一个外观类将子系统的复杂操作进行封装,客户端只需与外观类进行…

IO 多路复用是什么意思?Redis中的IO又是什么?

点击上方关注 “终端研发部” 设为“星标”,和你一起掌握更多数据库知识 本文首发于我的知乎:https://zhuanlan.zhihu.com/p/632776455 当你打开电脑,任何时候都在进行着IO的操作! 比如一次 API 接口调用、向磁盘写入日志信息&…

[数据结构习题]栈——中心对称链

[数据结构习题]栈——中心对称链 👉知识点导航💎:【数据结构】栈和队列 👉[王道数据结构]习题导航💎: p a g e 70.4 page70.4 page70.4 本节为栈和链表综合练习题 题目描述: 🎇思路…

Semaphore线程信号量

文章目录 前言一、Semaphore 是什么?定义对比 二、使用步骤1. 场景分析2. 编码如下 总结 前言 Semaphore 也是juc中的一个关键类,他与之前的lock 类似,也有公平和非公平两种,它与他们应用含义,引用场景有很大的不同; 与阻塞队列类似,但是也不一样;听我细细道来~ 一…

MTK capture 拍照流程

和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一、多帧拍照请求概览二、多帧拍照回帧概览 一、多帧拍照请求概览 多帧拍照请求概览如下: 多帧拍照请求 1.1 APP 下发拍照请求到 Camera Fr…

新Linux服务器安装Java环境[JDK、Tomcat、MySQL、Nacos、Redis、Nginx]

文章目录 JDK服务Tomcat服务MySQL服务Nacos服务Redis服务Nginx服务 说明:本文不使用宝塔安装 温馨提示宝塔安装命令:yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh JDK服务…

vitepress从0到1,让每个前后端小伙伴都拥有一个属于自己的博客

📸前言 之前周一的个人博客是用vuepress来搭建,但随着文章的数量越来越多,导致每回在启动的时候构建都特别慢,于是周一有了改构建工具的想法。这不,vitepress工具自发布后,在技术圈内一直有些火热&#xf…

数据库新闻速递 亚马逊Cosmos DB 添加了AI toolchain (译)

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共…

chatgpt赋能python:如何将Python代码打包成软件

如何将Python代码打包成软件 Python是一种直译式、交互式、面向对象的高级编程语言。由于其简洁明了的语法,Python在科学计算、Web开发、人工智能等领域得到了广泛的应用。但是,Python程序通常需要运行在特定的环境中,这限制了Python程序的移…

NodeJs之同源限制问题

1. 说明 app1是基于3001端口的服务器, app2是基于3002端口的服务器。 gitee地址:https://gitee.com/studyCodingEx/studys/ 2. app1 2.0 app1.js const express require(express); const path require(path); // 向其他服务器端请求数据的模块 const request …

Linux常用命令——gunzip命令

在线Linux命令查询工具 gunzip 用来解压缩文件 补充说明 gunzip命令用来解压缩文件。gunzip是个使用广泛的解压缩程序,它用于解开被gzip压缩过的文件,这些压缩文件预设最后的扩展名为.gz。事实上gunzip就是gzip的硬连接,因此不论是压缩或…

NodeJs之模板引擎及综合案例

0. 数据源 ./views/addtional.art {{ if age > 18 }}age > 18; {{ else if age < 15 }}age < 15; {{ else }}age!!!!!!!! {{/if}}<% if(age > 18){ %> 年龄大于18岁 <% } else if(age < 15) { %> 年龄小于15岁 <% } else { %> 其他年龄段…