改进rust代码的35种具体方法-类型(十六)-避免编写unsafe代码

上一篇的文章


Rust的内存安全保证(没有运行时开销)是其独特的卖点;它是任何其他主流语言中没有的Rust语言功能。这些保证是有代价的:编写Rust需要您重新组织代码以调整借入检查器,并精确指定您使用的参考类型。

Unsafe Rust是Rust语言的超集,它削弱了其中一些限制以及相应的保证。在带有unsafe关键字的块前缀会将该块切换到不安全模式,这允许正常Rust不支持的东西。特别是,它允许使用更像旧式C指针的原始指针。这些指针不受借阅规则的约束,程序员有责任确保它们在被取消引用时仍然指向有效内存。

因此,从表面上看,这个项目的建议是微不足道的:如果你只是在Rust中编写C代码,为什么要转到Rust?然而,在某些情况下,绝对需要unsafe代码:对于低级库代码,或者当您的Rust代码必须与其他语言的代码接口时。

不过,此项目的措辞相当精确:避免编写unsafe代码。重点是“写作”,因为很多时候,您可能需要的unsafe代码已经为您编写了。

Rust标准库包含许多unsafe代码;快速搜索在alloc库中发现了大约1000个unsafe的用途,在core的1500个,在std中还有2000个。该代码由专家编写,并因在数千个Rust代码库中使用而变得强硬。

其中一些unsafe代码发生在我们已经介绍过的标准库功能的封面下:

  • 第8项中描述的智能指针类型——RcRefCellArc和friends——在内部使用unsafe代码(通常是原始指针),以便能够向用户呈现其特定语义。
  • 下一篇中的同步原语——MutexRwLock和相关保护——在内部使用unsafe的操作系统特定代码。如果您想了解这些原语所涉及的微妙细节,建议使用Mara Bos(O'Reilly)的Rust Atomics和Locks

标准库还具有其他功能,涵盖更高级的功能,在内部unsafe的情况下实现:1

  • std::pin::Pin强制项目不在内存中移动(项目15)。这允许自我参考的数据结构,通常是新来者对Rust的bête noire
  • std::borrow::Cow提供写时克隆智能指针:同一指针可用于读取和写入,并且只有当发生写入时,才会发生基础数据的克隆。
  • std::mem中的各种功能(takeswapreplace)允许操作内存中的项目,而不会与借入检查器相冲突。

这些功能可能仍然需要谨慎才能正确使用,但unsafe的代码已被封装,以消除整类问题的方式。

超越标准库,crates.io生态系统还包括许多封装unsafe代码的板条箱,以提供常用功能:

  • once_cell:提供一种具有全局变量的方法,正好初始化一次。
  • rand:提供随机数生成,利用操作系统和CPU提供的低级底层功能。
  • byteorder:允许将原始数据字节转换为数字和从数字转换。
  • cxx:允许C++代码和Rust代码互操作。

还有很多其他的例子,但希望总体想法是明确的。如果您想做一些明显不符合Rust约束的事情,请浏览标准库,看看是否有现有功能可以满足您的需要。如果你没有找到你需要的东西,也可以尝试通过crates.io进行狩猎。毕竟,遇到一个其他人从未遇到过的独特问题是不寻常的。

当然,总会有unsafe的地方是被迫的,例如,当您需要通过外函数接口(FFI)与其他语言编写的代码进行交互时。但当有必要时,考虑编写一个包装层,其中包含所需的所有unsafe代码,以便其他程序员可以遵循本项目中给出的建议。这也有助于定位问题:当出现问题时,unsafe的包装可能是第一个嫌疑人。

此外,如果您被迫编写unsafe代码,请注意关键字本身隐含的警告:Hic sunt dracones

  • 添加安全注释,记录unsafe代码所依赖的先决条件和不变量。Clippy有一个警告来提醒你这一点。
  • ​尽量减少不安全块中包含的代码量,以限制错误的潜在爆炸半径。考虑启用unsafe_op_in_unsafe_fn检测,以便在执行不安全操作时需要显式的unsafeblock,即使这些操作是在本身不安全的函数中执行的。

  • 编写比平时更多的测试。
  • 在代码上运行其他诊断工具。特别是,考虑在您的unsafe代码上运行Miri——Miri解释编译器的中级输出,这允许它检测Rust编译器不可见的错误类。
  • 仔细考虑多线程的使用,特别是如果有共享状态。

添加unsafe标记并不意味着不适用规则——这意味着(程序员)现在负责维护Rust的安全保证,而不是编译器。


1在实践中,大多数std功能实际上是由core提供的,因此可用于之后文章中描述的no_std代码。

  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值