在Windows中使用Rust
本周六(11月9日),微软工程师Ryan Levick和Sebastian Fernandez将在RustFest Barcelona会议上发表主题演讲。他们将讨论微软探索采用Rust的原因、在此过程中遇到的一些挑战,以及Rust在微软的未来发展。如果您想与正在研究如何改进微软代码实践以提升安全性的人员交流,请务必参加主题演讲,并在会后与Ryan和Sebastian交谈!
这篇博客描述了微软采用Rust的部分故事。最近,我负责对Windows代码库中的一个低层系统组件进行实验性重写(抱歉,目前还不能透露是哪个组件)。我没有用C++重写代码,而是被要求使用Rust——一种内存安全的替代方案。尽管项目尚未完成,但我可以说,我对Rust的体验总体上是积极的。对于那些希望避免常见错误(这些错误通常导致C++代码库中的安全漏洞)的人来说,Rust是一个很好的选择。
出色的开发体验
对于习惯编写复杂系统的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团队