golang提案,内置 Go 错误检查函数

先来狠狠吐个槽

要吐槽 Go1 的 error ,那咱得先整明白大家为啥都猛喷它的错误处理做得不咋地。在 Go 语言里头,error 本质上其实就是个 Error 的接口:

复制代码
type error interface {
    Error() string
}

实际的应用场景如下:

复制代码
func main() {
 x, err := foo()
 if err != nil {
   // handle error
 }
}

单瞅这个例子,感觉好像没啥大毛病,可要是工程规模一变大,那可就不得了啦!

很明显,if err!= nil 这种逻辑在工程代码里那是扎堆出现,Go 代码里的 if err!= nil 甚至能占到工程代码量的 30% 还多呢:

复制代码
func main() {
	r1, err := fun1()
	if err != nil {
	  // handle error
	}
	r2, err := fun2()
	if err != nil {
	  // handle error
	}
	r3, err := fun3()
	if err != nil {
	  // handle error
	}
	r4, err := fun4()
	if err != nil {
	  // handle error
	}
}

猛这么一对比,4行函数调用,12行错误处理,这可真是让人头大呀!

另外呀,既然是错误处理,那肯定不只是简简单单地return err 这么回事儿。在工程实践中,项目代码那都是层层嵌套的,如果直接写成:

复制代码
if err != nil {
    return err
}

在实际工程里,这可绝对不行。您说您咋能知道具体是哪儿抛出的错误信息呀,实际出错的时候那只能是瞎蒙乱猜。所以就得加上各种描述信息:

复制代码
if err != nil {
    return fmt.Errorf("xxx, error: %s", err.Error())
}

try 函数

在 golang 的提案里,介绍了一种新的内置函数"try",这小家伙的出现是为了简化 Go 程序里那让人头疼的错误处理流程,同时还能保住语言的简洁明快和直截了当。try提供了一种神奇的机制,能让常见的错误检查模式表达得更简洁明了,把那些烦人的样板代码都给减少了,让代码的可读性和可维护性都蹭蹭往上涨。

虽说当前 Go 语言通过返回错误作为结果来处理错误的方式简单又灵活,但是在实际操作中,大量的错误检查代码常常让代码变得又长又复杂,就像一团乱麻,让人很难快速搞懂其中的逻辑流程。特别是在函数链里有好几个可能返回错误的步骤时,错误传播和处理的代码能占程序的一大部分,简直是"鸠占鹊巢"。

try 表达式

引入了一个新的内置函数try,它接收一个可能返回错误的表达式当参数,要是这个表达式执行成功(也就是没返回错误),那就返回表达式的值。要是表达式返回了一个错误,那try会立马"翻脸",终止当前函数的执行,把错误毫不留情地返回给调用者。它的语法是这样的:

复制代码
result := try expression

x1, x2, ... xn = try(f())

等同于下面的代码

复制代码
t1, ... tn, te := f()  // t1, ... tn, te are local (invisible) temporaries
if te != nil {
        err = te     // assign te to the error result parameter
        return       // return from enclosing function
}
x1, ... xn = t1, ... tn  // assignment only if there was no error

demo

来瞧瞧下面这个例子,展示了咋用try来简化文件读取操作的错误处理:

复制代码
func ReadData(filename string) ([]byte, error) {
    f, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer f.Close()
    
    data, err := ioutil.ReadAll(f)
    if err != nil {
        return nil, err
    }
    
    return data, nil
}

try可以简化成这样:

复制代码
func ReadData(filename string) ([]byte, error) {
    f := try os.Open(filename)
    defer f.Close()

    data := try ioutil.ReadAll(f)
    return data, nil
}

总结

  • 错误传播:try直接就让包含它的函数"缴械投降",然后返回错误,这就意味着它不能用在错误发生后还想"垂死挣扎"继续执行的场景里。
  • 控制流影响:因为try导致的提前"打退堂鼓",开发者得瞪大眼睛留神它对局部变量的生命周期和资源管理的影响。
  • 简洁与清晰:虽说try减少了错误检查的显式代码,可要是过度使用,可能会影响代码的可读性,特别是在复杂得像迷宫一样的逻辑里。

try这个内置函数是对 Go 错误处理模型的一个补充,目标就是提供一种更简练的错误处理方式,同时保持语言的其他核心特性不变。

资料

相关推荐
小破农2 分钟前
C++篇——多态
开发语言·c++
Q_Q19632884754 分钟前
python的漫画网站管理系统
开发语言·spring boot·python·django·flask·node.js·php
言之。5 分钟前
Go 语言中接口类型转换为具体类型
开发语言·后端·golang
咖啡の猫6 分钟前
JavaScript基础-创建对象的三种方式
开发语言·javascript·ecmascript
代码不停13 分钟前
Java二叉树题目练习
java·开发语言·数据结构
77tian27 分钟前
VMware中快速安装与优化Ubuntu全攻略
开发语言·ubuntu
愚润求学1 小时前
【Linux】进程间通信(一):认识管道
linux·运维·服务器·开发语言·c++·笔记
{⌐■_■}1 小时前
【gRPC】HTTP/2协议,HTTP/1.x中线头阻塞问题由来,及HTTP/2中的解决方案,RPC、Protobuf、HTTP/2 的关系及核心知识点汇总
网络·网络协议·计算机网络·http·rpc·golang
珊瑚里的鱼1 小时前
【滑动窗口】LeetCode 1658题解 | 将 x 减到 0 的最小操作数
开发语言·c++·笔记·算法·leetcode·stl
晚秋大魔王1 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——wget
java·linux·运维·开发语言·华为·harmonyos