在Windows中使用Rust
本周六11月9日,微软工程师Ryan Levick和Sebastian Fernandez将在RustFest Barcelona发表主题演讲。他们将讨论微软探索采用Rust的原因、在此过程中面临的一些挑战,以及Rust在微软的未来应用。如果您想与致力于改进微软代码实践以提升安全性的人员交流,请务必参加主题演讲并与Ryan和Sebastian会后交谈!
本篇博客描述了微软采用Rust的部分故事。最近,我负责对Windows代码库中的一个低级系统组件进行实验性重写(抱歉,目前还不能具体说明是哪一个)。我没有使用C++重写代码,而是被要求使用Rust这种内存安全的替代方案。尽管项目尚未完成,但我可以说我对Rust的体验总体上是积极的。对于那些希望避免常见错误(这些错误通常导致C++代码库中的安全漏洞)的人来说,这是一个很好的选择。
出色的开发体验
对于习惯编写复杂系统的C++开发者来说,使用Rust开发是一种清新的体验。编译器提供的内存和数据安全保证使开发者更有信心,编译后的代码不仅避免内存安全漏洞,还能确保正确性。更少的时间花费在调试琐碎问题或令人沮丧的竞争条件上。编译器的警告和错误信息写得非常好,让新手Rust程序员能够快速识别和解决代码中的问题。VSCode已经有一个有用的扩展(RLS),提供Intellisense建议和语法高亮。此外,Cargo构建工具在测试、文档生成和自动格式化方面提供了非常有用的功能。
学习曲线
得益于丰富的在线文档和非常有用的编译器错误信息,对于像我这样职业生涯大部分时间使用C++的人来说,Rust的学习曲线相当平缓。有针对C/C++系统工程师的专门教程。在RustConf 2019的演讲中,Facebook的Jeremy Fitzhardinge指出,他看到有经验的C/C++开发人员在大约四周内对Rust感到舒适,并在八周内相当流利。这与我的个人经验一致。我参加了一年一度的微软内部“One Week”黑客马拉松,与一位有经验的Rust开发者和一位完全的新手合作。在三天内,新手Rust开发者编写了超过1000行地道的Rust代码。除了出色的文档,还有像Clippy这样的有用工具,让有经验的C++开发者无需太多Rust专家的直接帮助就能直接开始编写Rust代码。
随着我们在微软内部扩大Rust的使用,我认为明智的做法是启动一个RustReviewers小组,用于审查任何包含Rust代码的PR。这将帮助不同团队的新手从Rust专家那里获得反馈,无论具体问题领域如何。
总的来说,新组件或具有清晰接口的现有组件最容易移植到Rust。我一直在重写的组件具有挑战性,因为有许多抽象从一层泄漏到另一层,需要在取得进展之前进行一些初步的重构。
外部函数接口(FFI)
将Rust代码与C ABI(应用二进制接口)边界链接是直接的。对于使用基本类型的简单函数,需要编写的样板代码量很少。然而,鉴于FFI函数总是不安全的,总是需要包装函数。对于涉及更复杂结构体的函数,最好在构建过程中使用bindgen自动生成等效的Rust结构体。能够直接与C++互操作需要更多研究,尽管我们已经有团队在调查这一点。微软最近开源了一个COM库,我们视其为迈向这一步的第一步,但我们最终需要更高级的工具来直接与复杂的C++ API接口。
保持安全
为了从Rust获得所需的安全保证,必须围绕unsafe关键字的使用制定严格指南。任何对FFI函数的调用都应发生在一个包装函数中,该函数提供安全的抽象。类似地,任何其他必须使用unsafe关键字的代码应有一个提供安全抽象的包装函数或结构体。
在实践中,除了FFI边界,unsafe仅用于非常基本的协议处理。在这些情况下,编写一些通用的unsafe代码很简单,这些代码可以彻底进行单元测试并用于各种场景, resulting in code that feels much safer than C++. 在编写Rust代码后,我发现编写C++更加令人沮丧,因为我无法依赖编译器来确保内存安全。
除了确保安全保证之外,拥有一套内部Rust编码标准将帮助新开发者充分利用这门语言。错误处理、日志记录、锁定和其他语言特定问题的最佳实践将更快地获得更高质量的代码。
期望的功能和Rust社区
鉴于Rust相对年轻,仍然缺少一些对我们开发非常理想的语言功能。其中最主要的是安全转换(安全地将“普通旧数据”类型与原始字节相互转换)、对C风格联合体的安全支持以及可失败的分配(优雅地从分配失败中恢复,而不是恐慌)。
Rust的另一个惊人能力是Cargo内置的单元测试,允许开发者在与生产代码相同的文件中编写单元测试,并在开发过程中轻松运行它们。不幸的是,在我们庞大复杂的构建系统中,目前无法依赖Cargo作为构建工具,因此在没有进一步工作的情况下,我们无法在自动代码集成流程中依赖这些测试。已经与Cargo团队开始讨论,像微软这样拥有复杂现有构建系统的大公司如何仍然利用Cargo。
由于在微控制器和内核、虚拟机监控程序等低级系统中使用Rust的兴趣,社区已经在解决这些问题。我相信我们微软将能够帮助这些努力,塑造语言的未来,提高其在这些场景中的实用性。
从这里出发
总的来说,使用Rust是一次非常棒的体验。我期待看到更多微软的开发者使用这门语言,并与更广泛的社区合作,使这门语言更适应我们在微软所做的一些事情。
Adam Burch,软件工程师,Hyper-V团队