Rust的Option类型的开销是多少?


84

在Rust中,引用永远不能为null,因此在实际需要null(例如链表)的情况下,请使用以下Option类型:

struct Element {
    value: i32,
    next: Option<Box<Element>>,
}

与简单指针相比,就内存分配和取消引用的步骤而言,这涉及多少开销?在编译器/运行时中,是否有一些“魔术”可以使Option成本降低,或者比Option使用非核心库使用相同的enum构造自己实现或通过将指针包装在向量中实现成本更低?

Answers:


87

是的,在Option<ptr>大多数情况下,有一些编译器魔术可以优化为单个指针。

use std::mem::size_of;

macro_rules! show_size {
    (header) => (
        println!("{:<22} {:>4}    {}", "Type", "T", "Option<T>");
    );
    ($t:ty) => (
        println!("{:<22} {:4} {:4}", stringify!($t), size_of::<$t>(), size_of::<Option<$t>>())
    )
}

fn main() {
    show_size!(header);
    show_size!(i32);
    show_size!(&i32);
    show_size!(Box<i32>);
    show_size!(&[i32]);
    show_size!(Vec<i32>);
    show_size!(Result<(), Box<i32>>);
}

打印以下大小(在64位计算机上,因此指针为8字节):

// As of Rust 1.22.1
Type                      T    Option<T>
i32                       4    8
&i32                      8    8
Box<i32>                  8    8
&[i32]                   16   16
Vec<i32>                 24   24
Result<(), Box<i32>>      8   16

需要注意的是&i32Box&[i32]Vec<i32>全部采用内的非空的指针优化Option


38
此外,此优化发生在所有“ Option-like”枚举中,因此它也适用于用户定义的Option
Paul Stansifer

3
另请注意,此优化不能堆叠。可以在示例的最后一行看到。当您将Ok的类型指定为()时,该特定结果类型将成为“类似枚举的选项”,因此无法在选项级别进行优化。但是,如果尝试使用,Result<i32, i32>您将看到再次应用了优化。
Pajn

4
@Pajn看起来,至少到2020年3月,只要有足够多的否则无效的二进制表示形式,可以堆叠这种类型的优化。当然,非空指针通常只有一个无效的二进制表示形式。
Vaelus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.