最本质的区别是:Golang的错误处理是“积类型”,而的错误处理Rust 是“和类型”。Rust 的 Result 是一种 Monad,从理论上就决定了它比 Go 的多值返回要强大的多。Rust 的错误处理方式是利用了 Monad 概念与控制流操作符,而 Go 的多值返回更像是作者固执己见的设计。

Go 的错误处理是“积类型”,而 Rust 是“和类型”。这是最本质的区别。Golang 错误处理的设计从本质上讲就是错误的。ret 和 err 同时被定义,而在逻辑上,每次只有其中一个不是 nil(另一个 nil 无存在意义)

在实际使用中,当 err 是 nil 的时候,ret 也可以是 nil(均无值)

在实际使用中,当 err 不是 nil 的时候,ret 也可以不是 nil(均有值)

由于 Golang 到目前为止还无法直接定义“和类型”,如果 foo 可能返回两种错误 Error1 和 Error2,你没法保证调用者完全排除了这两种错误的可能性之后才使用数据。

而 Rust 采用了正确的设计,你只能返回一种:要么返回正确,要么返回错误。Golang 最本质的错误就是要求你同时返回两种。

和类型与积类型的区别虽然重要,但不是最主要的不同点。最主要的是,Rust 的 Result 是一种 Monad,从理论上就决定了它比 Go 的多值返回要强大的多。

有类似效果的是 JavaScript 的 Promise,它给回调式 API 来了一波全面打击。链式调用开火车比回调地狱爽多了。

但是 Monad 还不够,人们又折腾出了配套的控制流操作符。

Rust 的问号运算符一出现就把链式调用干翻了。不知道怎么处理错误?打个问号上抛就完事了。要更严谨一点就附加日志、错误消息或类型转换。JS 的 await 配合 Promise,用同步风格写异步,也是相同的道理。

总结,Rust 的错误处理方式是利用了 Monad 概念与控制流操作符,而 Go 的多值返回更像是作者固执己见的设计。

Rust 虽然以 Result 统一了错误表达,但没有统一解决错误链、栈回溯等问题。更强的表达力会带来更大的分裂,不同领域的项目有不同看法,嵌入式项目和 Web 项目显然玩不到一起去。目前最接近大一统目标的是 anyhow 和 thiserror 两个库。其中 anyhow 的 Error 与 Go 的错误接口等效。

Go 的错误处理虽然看起来简陋,但基本实现了统一。我们先不管把 panic/recover 当 throw/catch 用的人。从语言设计的角度,Rust 无疑更好。但从软件工程的角度,各有各的看法,worse is better 再次生效。

延伸阅读:

什么是Golang?

Go(又称 Golang)是 Google 的 Robert Griesemer,Rob Pike 及 Ken Thompson 开发的一种静态强类型、编译型语言。Go 语言语法与 C 相近,但功能上有:内存安全,GC(垃圾回收),结构形态及 CSP-style 并发计算。

Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。

罗伯特·格瑞史莫(Robert Griesemer),罗布·派克(Rob Pike)及肯·汤普逊(Ken Thompson)于2007年9月开始设计Go,稍后Ian Lance Taylor、Russ Cox加入项目。Go是基于Inferno操作系统所开发的。Go于2009年11月正式宣布推出,成为开放源代码项目,并在Linux及Mac OS X平台上进行了实现,后来追加了Windows系统下的实现。在2016年,Go被软件评价公司TIOBE 选为“TIOBE 2016 年最佳语言”。 目前,Go每半年发布一个二级版本(即从a.x升级到a.y)。

Go的语法接近C语言,但对于变量的声明有所不同。Go支持垃圾回收功能。Go的并行模型是以东尼·霍尔的通信顺序进程(CSP)为基础,采取类似模型的其他语言包括Occam和Limbo,但它也具有Pi运算的特征,比如通道传输。在1.8版本中开放插件(Plugin)的支持,这意味着现在能从Go中动态加载部分函数。