Rust的错误处理可能已经领先别的语言两层了,但我们甚至还没有看到终点在哪

RustConf 2020其中一场关于错误处理的报告实在是太精彩了,解决了我遇到过的很多问题,或者至少展示了前进的方向。比如,我以前用Python时写过一个subprocess的wrapper,和报告中的output2功能几乎一样,而现在我们有了Error Reporter的概念。顺便一提,应该使用ui test来测试错误输出。

但不得不说,关于错误处理,还有很多难点。这里简单地谈一下我的经验和思考。

Recoverable and unrecoverable Errors

这是一个已经被聊烂了的话题:程序bug触发panic,例如数组越界;正常行为返回Result,例如文件不存在。但实践中这个界限并不是那么清晰,例如从HashMap取值,常常就写为 &map[key],当key不存在于map中时就会panic。这个和文件不存在其实是非常相似的,那么是不是进行类似的处理就解决了呢?最大的问题在于&map[key]这种写法实在是太方便了,写成map.get(key).expect(&format!("{} not exists {}", key))就已经非常讨厌了(这么写无论是否出错都会构造错误消息,但我不知道更好的写法了,并没有一个expect_with方法);而要写成“正确”的形式map.get(key).ok_or(...)?,你需要构造一个Error,修改当前的函数返回Result,再处理一圈调用了此函数的代码,这实在是太考验人性了,而人性从来是经不起考验的。目前看来,我觉得最好的办法是标一个todo,然后视需求来处理这些todo:如果是小玩具,那就永远todo吧;如果是本地小工具,那就panic了若干次后进行修改,具体次数取决于你的耐性;如果是对正确性和响应要求高的正式项目,那就抽时间集中处理。

再明确一下,我认为&map[key]这种就类似于unwrap,除非逻辑上不可能出错出错了就意味着程序bug,在正式代码里是不应该出现的;尽量使用Error而不是panic。

Fehler

当然我们还是有一些办法来缓解这个问题的。其中我觉得正确得很明显的一个是fehler,Ok-Wrapping实在是太香了,把一个函数从返回T改成返回Result<T, E>只需要加一行attribute。

Anonymous sum types

定义error type是另一个痛点。很多时候一个crate只有一个error type,我理解这是人在懒惰和正确之间做的一个妥协。看到相当一部分人觉得snafu是优于thiserror的库,比如最近有这篇文章;我还没有仔细地对比过两者,但至少有一点我觉得snafu很正确:每个moduel都有单独的Error,而不是整个crate只有一个。更极端地说,我认为(几乎)每个函数都应该有一个Error。这样当然非常繁琐,对于想偷懒的人,Anonymous sum types会非常有用 。而anyhow!这种一次性的error type,本质上就是一种只能用于报告的error type,可能大部分用处都会被取代。

Errors intended for an application's user and errors intended to be handled by code

两者的界限同样并不是特别清晰,原来写在main.rs里的函数可能会被放到单独的文件里,然后再被提取为单独的library。极端一点,所有binary crate的main.rs都应该只是对同级的lib.rs的简单调用,所以理论上几乎不存在仅仅展示用的Error。当然实际上的情况往往恰好相反,能够用anyhow!返回字符串而不是直接unwrap就已经很好了。不过我还是同意应该区分纯报告给用户(于是可以偷懒!)的error和需要代码处理的error的,但区分的标准不是这个error产生于library还是application,而是语义上这个error应该如何处理:library也可以产生前一种error,application也可以产生后一种error。

Warning

Warning是一个Rust社区很少讨论的和error很接近的概念。它们可能会互相转化,之前觉得是硬错误的问题,后来觉得可以继续执行只要log输出一下就行了,反之亦然。核心的一点是,warning同样会需要context、source、backtrace这些以帮助人理解发生了什么。我用过w_result这个库,还是挺好用的。

Vec<Error>

Vec<Warning>的概念比较明显,同样的也有Vec<Error>的问题,调用者有可能需要一次性收集所有错误(尤其是要报告给人的时候)。某种意义上,error可以分为中断性的error和可以继续于是可收集的error,而这两者有时也是根据语义的。而Result<T, Vec<Error>>是和Result<T, Error>不兼容的;或许每个Error Enum都应该有一个List的variant?我知道一个相关的库beau_collector,但它的适用范围并不广。

Async Error

Elm之前版本的教程里提到了用Task优雅地处理异步错误,但具体内容一直是comming soon,然后最新版本整个Error Handling一章都消失了。顺便一提,Rust现在如此优秀的编译错误提示也是来源于elm的。回到Rust,以我极为有限的了解,基本最终还是panic了事。这事可能还没人想明白。

Conclusion

<del>Errors are annoying</del>

整理了一下思路,感觉中断性/可以继续的error/warning可能全都是同一个东西。一个返回T的函数,其实应该返回WResult<T, E, E>,其中E大概是这样的定义:

enum Error {E1,E2,List(Vec<Box<Error>>),
}

函数自身决定返回WOk还是WErr,调用者在收到WErr时只能继续传播或处理,而收到带Warning的WOk时,根据每个具体的Error决定传播(加入自己的Warning或Error列表)还是处理(打log、哪怕是直接丢弃)。近期争取抽空来测试一下这个想法。

rust地基蓝图在哪找_Rust错误处理的思考相关推荐

  1. rust地基蓝图在哪找_深海迷航蓝图在哪 深海迷航全蓝图及碎片详细坐标位置介绍...

    深海迷航蓝图在哪 深海迷航全蓝图及碎片详细坐标位置介绍 2017-12-29 16:49:08来源:游戏下载编辑:云曼衍评论(0) <深海迷航>是一款水下探险类游戏,游戏里面有很多收集元素 ...

  2. 别让数据坑了你!用置信学习找出错误标注(附开源实现)

    星标/置顶小屋,带你解锁 最萌最前沿的NLP.搜索与推荐技术 文 | JayLou娄杰(NLP算法工程师,信息抽取方向) 编 |  北大小才女小轶 美 | Sonata 1 前言 在实际工作中,你是否 ...

  3. 项目成功的关键是在投资最少的时候找出错误

    1 项目成功的关键是在投资最少的时候找出错误. 2 如果在给一个程序找个好名字时感到困难,往往是对这一子程序的功能还不够清楚. 3 编写工作应该从抽象到具体. 4 在确定程序是正确的之前,不要急于编译 ...

  4. 里rust怎么找蓝图_Rust错误处理

    错误处理是程序开发中必不可少的一个环节,在Rust中,错误分成两个类别:可恢复错误和不可恢复错误. 可恢复错误:比如说未找到文件,Rust中用Result<T,E>来实现 不可恢复错误:比 ...

  5. rust为什么显示不了国服_Rust编程语言初探

    静态.强类型而又不带垃圾收集的编程语言领域内,很久没有新加入者参与竞争了,大概大部分开发者认为传统的C/C++的思路已经不太适合新时代的编程需求,即便有Ken Tompson这样的大神参与设计的gol ...

  6. 如何找出错误ora-07445发生时系统执行的语句

    在trace file中查找错误出现时的语句主要分两个步骤:首先找到错误发生时的执行语句,然后需要找到语句中绑定变量的值.Step 1:Find the SQL在跟踪文件中查找字符串"Cur ...

  7. rust门卡有什么用_Rust能力养成之(10)用Cargo进行项目管理:扩展 调用与优化

    前言 上一篇我们讲了Cargo运行测试 Cargo运行实例 Cargo工作空间 当然,Cargo也能够进行扩展,合并外部工具以增强开发体验,在设计上,其可扩展性已经达到非常丰富和恰当的程度.Cargo ...

  8. rust相框加载图片代码_Rust 能取代 Python,更好的实现神经网络?

    Rust 也能实现神经网络? 作者 | Nathan J. Goldbaum译者 | 弯月,责编 | 屠敏出品 | CSDN(ID:CSDNnews)以下为译文:我在前一篇帖子(http://neur ...

  9. rust火箭基地主楼开启方法_Rust 为什么能成为 Stack Overflow 最受欢迎的语言?

    每年,开发者问答网站 Stack Overflow 都会对程序员社区展开年度调查,包括他们最喜爱的技术到工作偏好的所有内容. 在2017 年和2018 年Stack Overflow 年度开发者调查中 ...

最新文章

  1. 佛山居住证办理(首次)
  2. 40亿移动设备的用户画像和标签架构实践
  3. 重磅 !间隔分析正式上线,神策数据分析能力再度增强
  4. php Function split() is deprecated 的解决办法(转)
  5. php如何判断提交内容为空,php禁止提交空表单(php空值判断)的方法
  6. Intellij IDEA关闭 Build窗口提示
  7. Catalyst 6509交换机配置方案
  8. 【转】Python可变长度的函数参数
  9. GIS实战应用案例100篇(十五)-CASS插件应用:如何控制点属性与点名统一
  10. 构建了我的第一个React Native应用程序之后,我现在确信这是未来。
  11. 监听是否到达页面滑动的可视区域最底部
  12. oppo手机计算机,OPPO手机助手
  13. 重新认识javascript的settimeout和异步
  14. 清除所有多余的桌面右键菜单
  15. DOM和Events
  16. kali linux2019镜像下载,Kali 2019下载_KaLi Linux镜像文件iso下载 2019.1a x86/x64_当载软件站...
  17. 把pdf转为高清jpg图片,其dpi为300以上
  18. linux 消息队列实现通信
  19. 手机QQ邮箱可以发html邮件么,如何使用手机qq邮箱发送邮件
  20. odd ratio置信区间的计算,你学会了吗?

热门文章

  1. python中有那几种赋值_详解Python列表赋值复制深拷贝及5种浅拷贝
  2. php速度慢不怕cpu漏洞,PHP曝远程DOS漏洞可致CPU持续占满,请注意升级_护卫神
  3. img解包打包工具_Python开发GUI实战:图片转换素描画工具!
  4. python常用第三方模块多少万_python 常用第三方模块
  5. 如何调整标题字体大小_软网推荐:找回调整Windows 10字号功能
  6. oracle java javapath_系统找不到C:\ProgramData\Oracle\Java\javapath\java.exe问题及解决方案...
  7. 关于ios在H5页面长按识别二维码无效
  8. vim之添加多行和删除多行
  9. Hibernate异常之关键字错误
  10. Map集合HashMap,TreeMap