Was ist der Overhead des Optionstyps von Rust?

83

In Rust können Referenzen niemals null sein. Wenn Sie also tatsächlich null benötigen, z. B. eine verknüpfte Liste, verwenden Sie den OptionTyp:

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

Wie viel Overhead ist damit in Bezug auf die Speicherzuweisung und die Schritte zur Dereferenzierung im Vergleich zu einem einfachen Zeiger verbunden? Gibt es eine "Magie" im Compiler / zur Laufzeit, die Optionkostenlos oder kostengünstiger zu machen ist , als wenn man sie Optionselbst in einer Nicht-Kernbibliothek mit demselben enumKonstrukt implementieren oder den Zeiger in einen Vektor einschließen würde?

Thilo
quelle

Antworten:

85

Ja, es gibt einige Compiler-Magie, die Option<ptr>(meistens) auf einen einzelnen Zeiger optimiert wird .

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>>);
}

Die folgenden Größen werden gedruckt (auf einem 64-Bit-Computer, also sind Zeiger 8 Byte):

// 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

Beachten Sie, dass &i32, Box, &[i32], Vec<i32>alle nutzen die Nicht-Nullable - Zeiger - Optimierung innerhalb ein Option!

huon
quelle
38
Darüber hinaus erfolgt diese Optimierung in allen " Optionähnlichen" Aufzählungen, sodass sie auch für eine benutzerdefinierte Aufzählung funktioniert Option.
Paul Stansifer
3
Beachten Sie auch, dass diese Optimierung nicht gestapelt werden kann. Dies ist in der letzten Zeile des Beispiels zu sehen. Wenn Sie den Typ für Ok als () angeben, wird dieser bestimmte Ergebnistyp zu einer "Option wie enum" und kann daher nicht auf Optionsebene optimiert werden. Wenn Sie es jedoch versuchen Result<i32, i32>, können Sie sehen, dass die Optimierung erneut angewendet wird.
Pajn
4
@Pajn Es sieht aus wie, zumindest ab März 2020 diese Art der Optimierung kann gestapelt werden , solange es genug ansonsten ungültige binäre Darstellungen sind. Natürlich haben nicht nullfähige Zeiger normalerweise nur eine ungültige binäre Darstellung.
Vaelus