【问题标题】:How to find biggest variant in an enum in Rust?如何在 Rust 的枚举中找到最大的变体?
【发布时间】:2019-11-14 12:30:01
【问题描述】:

我正在尝试提高 rust 程序的性能,这需要我减小一些较大的 enums 的大小。例如

enum EE {
    A, // 0
    B(i32), //4
    C(i64), // 8
    D(String), // 24
    E { // 16
        x: i64,
        y: i32,
    },
}

fn main() {
    println!("{}", std::mem::size_of::<EE>()); // 32
}

打印32。但是如果我想知道EE::A 的大小,就会出现编译错误

error[E0573]: expected type, found variant `EE::A`
  --> src/main.rs:14:40
   |
14 |     println!("{}", std::mem::size_of::<EE::A>());
   |                                        ^^^^^
   |                                        |
   |                                        not a type
   |                                        help: try using the variant's enum: `crate::EE`

error: aborting due to previous error

error: could not compile `play_rust`.

有没有办法找出哪个变体占用的空间最多?

【问题讨论】:

  • “有没有一种有效的方法来获取每个枚举变量的大小?” → 所有变体都有相同的大小,对应枚举的大小。
  • @mcarton "所有变体都具有相同的大小",这取决于消耗最多内存的变体的大小,如果我能快速找到该变体,我可以快速改进我的枚举定义。我想请问如何快速找到那个变种,不好意思我表达不好。
  • @mcarton 在上面的例子中,D(String) 需要最多的内存大小,即 24,所以枚举的大小是 (24 + 8) = 32。如果我用 @ 替换 D(String) 987654328@,枚举的大小可以减少到16。如果rust可以告诉我D(String)使用24字节,这是所有变体中最大的一个,所以枚举大小应该是32字节,如果D(String) 的大小可以减小,枚举的大小也可以减小。
  • @mcarton 虽然您在技术上是正确的,但我认为您正在分裂头发,并且很清楚 OP 的意图。甚至还有一个 Clippy lint 用于“枚举变量之间的大尺寸差异”,因为有一个枚举大小和每个变量的空间利用率的概念。
  • 切线地,在类似示例的情况下,您也可以使用Box&lt;str&gt;,它与Box&lt;String&gt; 基本相同,但只占用 16 个字节,因此整个枚举可以容纳 24 个字节,同时避免双重间接成本。很少有充分的理由使用Box&lt;String&gt;

标签: memory enums rust


【解决方案1】:

不,没有办法只获得enum 的一个变体的大小。您可以做的最好的事情是获取变体包含的大小,就好像它是一个独立的结构一样:

    println!("sizeof EE::A: {}", std::mem::size_of::<()>());         // 0
    println!("sizeof EE::B: {}", std::mem::size_of::<i32>());        // 4
    println!("sizeof EE::C: {}", std::mem::size_of::<i64>());        // 8
    println!("sizeof EE::D: {}", std::mem::size_of::<String>());     // 24
    println!("sizeof EE::E: {}", std::mem::size_of::<(i64, i32)>()); // 16

即使这也不是特别有用,因为它包含可用于存储标签的填充字节;正如您所指出的,如果 D 缩小为单个指针,则 enum 的大小可以减少到 16,但是您不能仅从大小中知道这一点。如果将y 定义为i64,则每个变体的大小将相同,但enum 的大小需要为24。对齐是导致enum 大小的另一个混杂因素比“最大变体的大小加上标签”更复杂。

当然,这都是高度依赖于平台的,你的代码不应该依赖任何具有特定布局的enum(除非你可以用#[repr]注解保证它)。

如果您担心某个特定的enum,那么获取每个包含类型的大小并不难。 Clippy 还为enums 提供了一个 lint,其变体之间的大小差异很大。但是,我不建议单独使用 size 对 enum 布局进行手动优化,或者对大小只有几个指针的东西进行装箱——间接抑制了编译器可能能够执行的其他类型的优化。如果您优先考虑最小的空间使用,您可能会意外地使您的代码在此过程中变慢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多