在 Rust 中使用 unsafe 和联合体设计高效的内存布局,或者,一篇避免动态调度的冗长指南

这是一篇关于在 Rust 语言中构建命令行电子表格程序的系列博客的第一篇,主要介绍了电子表格单元格中值的内存布局设计。

  • 引言:面向熟悉 Rust 语言且了解典型 Rust 数据结构在内存中布局的人,本文将设计电子表格单元格中每个值的内存布局,单元格可包含数字、字符串、公式或迭代器等。
  • 首次尝试:动态分发:朴素方法是使用enum,但为了教学目的,先通过动态分发建模,定义了一个CellValue trait 并实现了DisplayAny,还定义了各种类型如DynCellValueNumStrFormulaIter等,得出Iter有两个动态分发间接层,然后讨论了这种方法的缺点,如Box<dyn CellValue>的分配慢且有不必要的间接层。
  • 枚举分发:这是在使用动态分发之前应尝试的方法,enum_dispatch crate 可自动处理dyn Trait的所有类型,定义了CellValue枚举并实现了Display,但发现数字Long不是单个字,需要改进。
  • 十进制数字类型,ft 标记指针:介绍了Long的正确名称为Decimal,是一种更精确适合财务计算的数字,利用标记指针的特性来存储enum的标签,解释了标记指针超出本文范围,推荐阅读相关文档和源代码。
  • 现在使用联合,也称为 C 的无标记枚举或 Friedrich Transmute:联合是枚举的支持数据,可定义一组可被多种类型使用的数据,但每次只能使用一种。复制了之前的enum,添加了ManuallyDropTaggedPtr来处理非Copy类型,手动实现iterdyn,选择标签的位掩码,实现了从联合中获取值的功能,并展示了如何获取数字、字符串和公式等。
  • 结论:联合不仅是古老的工具,在合适的情况下仍能产生惊人的结果,但在使用过程中要注意安全性和正确性。

总体而言,本文详细介绍了在 Rust 中设计电子表格单元格值的内存布局的过程,从不同的方法到最终使用联合的实现,展示了 Rust 语言在内存管理和类型系统方面的特点和技巧。

阅读 9
0 条评论