本文为『Zino开发框架技术解读』系列的第二篇。

在Zino开发框架中,我们定义了一个通用的错误类型Error,主要目的是实现以下功能:

  1. 基于字符串将任意错误包装成同一类型;
  2. 支持source,并能溯源到原始错误;
  3. 支持tracing,自动记录错误信息。

这三条需求对于Zino框架至关重要,这也是为什么我们没有采用社区中的错误处理库,比如anyhow。在实际应用开发中,我们往往并不会对具体的错误类型做不同的处理,而是直接返回错误消息,所以我们采取基于字符串的错误处理:
其中SharedString是Zino中用来优化静态字符串处理的类型。很多人认为Rust标准库中的String类型就应该定义成Cow<'static, str> (当然,这又是一个性能和使用便利性的取舍问题)。所以,我们的Error类型对于静态字符串的处理有巨大的性能优势,后期的bench也验证了这一点:
zino::error::Error在处理 &'static str消息时只需要2.5ns;相比之下,anyhow::Error需要60ns

Error类型的方法实现就很直接了当:其中 .sources() 返回的是一个迭代器,在anyhow中称为Chain(我们这里的命名与核心库中的core::error::Source保持一致)。

至此,我们实现了错误溯源的功能,并提供了 .root_source() 方法来追溯到原始错误。接着,我们需要将任一错误类型E: std::error::Error + 'static转换为Error类型(其中 'static的生命周期限制是必须的,这是std::error::Error::source() 方法的要求):这样,我们就可以在需要返回Result<T, zino::error::Error> 的函数中方便地使用 ? 运算符(注意,我们的Error类型本身并没有实现std::error::Error)。

剩下的最后一个核心功能就是如何与tracing集成,让它自动记录错误信息:这里的关键就是实现std::fmt::Display。每当我们调用 .to_string() 时,tracing::error就会自动生成一条记录:

全部代码加起来就一百行左右:

清晰易懂,简洁优雅!


photino
17 声望3 粉丝