【问题标题】:Why does Rust use two bytes to represent this enum when only one is necessary?为什么在只需要一个字节时,Rust 使用两个字节来表示这个枚举?
【发布时间】:2019-06-27 04:35:03
【问题描述】:

它似乎足够聪明,只为 A 使用一个字节,但不够聪明,无法为 B 使用一个字节,即使只有 8*8=64 种可能性。有什么方法可以哄 Rust 解决这个问题,还是我必须手动实现更紧凑的布局?

Playground link.

#![allow(dead_code)]

enum A {
    L,
    UL,
    U,
    UR,
    R,
    DR,
    D,
    DL,
}

enum B {
    C(A, A),
}

fn main() {
    println!("{:?}", std::mem::size_of::<A>()); // prints 1
    println!("{:?}", std::mem::size_of::<B>()); // prints 2
}

【问题讨论】:

  • 这是因为 rust 的枚举是其最大变体的大小。在这种情况下,Au8 的大小,因此需要 两个 个字节来适应 B 中的 两个 As,如没有像这样的编译时微优化。无论如何,如果打包版本的使用速度比解压版本慢怎么办?
  • 一句话,实现的行为。
  • @OptimisticPeach:在某些平台/用例上肯定会更糟,但是现在内存延迟通常较小的数据结构通过减少缓存未命中来弥补任何解包时间。我将拥有相当大的这些对象的向量,我将半随机访问,因此缓存未命中是我的用例的一个问题。我可以选择一些我必须选择的东西,但这仍然可以节省我自己手动执行打包逻辑的工作。
  • Rust 可以在一些更有限的情况下进行枚举布局优化,例如见github.com/rust-lang/rust/pull/45225

标签: enums rust memory-layout


【解决方案1】:

为了保持借用结构成员的能力,这两个字节都是必需的。

Rust 中的类型不是一组理想的值:它有一个数据布局,它描述了值的存储方式。管理该语言的“规则”之一是,将类型放入 structenum 不会改变其数据布局:它在另一种类型中的布局与它独立时的布局相同,这允许您获取引用构造成员并将它们与任何其他引用互换使用。*

在满足此约束的同时,无法将两个As 放入一个字节中,因为A 的大小是一个完整字节——即使使用repr(packed),您也无法寻址一个字节的一部分.未使用的位保持未使用(除非它们可以通过适当的填充重新用于存储枚举标签)。

*好吧,repr(packed) 实际上可以使这不真实。 Taking a reference to a packed field can cause undefined behavior,即使在安全代码中!

【讨论】:

  • 我想知道是否有可能拥有某种宏来对 B 进行紧凑表示,这将涉及生成 A 的多种可能表示并为您实现两全其美的转换。 ..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-11
  • 2017-08-25
  • 1970-01-01
  • 2015-04-02
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
相关资源
最近更新 更多