web-dev-qa-db-ja.com

Rustのオプションタイプのオーバーヘッドはどれくらいですか?

Rustでは、参照がnullになることはないため、リンクリストのように実際にnullが必要な場合は、Option型を使用します。

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

単純なポインターと比較して、メモリの割り当てと逆参照の手順に関して、これにどのくらいのオーバーヘッドが関係していますか?コンパイラ/ランタイムにOptionを無料にする、または同じOptionコンストラクトを使用して非コアライブラリに自分でenumを実装する場合、またはポインターをベクトルにラップする場合よりも低コストにするための「マジック」があります?

70
Thilo

はい、最適化するコンパイラの魔法があります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!内でnull不可のポインター最適化を使用します。

71
huon

この回答は現在廃止されています。 _Option<T>_の判別式は、可能な限り最適化されています。(ただし、提供される情報の残りの部分はまだ興味深いです。)

現時点では、Option型は、他のenum型と同じ量のスペースを占有します。私は詳細を知りませんが、それは確かにある種の差別化された組合として表されます。

最適化のために内部表現を微調整する可能性は、Rust開発者によって検討されています。

パトリックウォルトンが投稿した devメーリングリストの関連する議論 です。

ここにはコンパイラの最適化の余地がたくさんあるので、列挙型の特定のビット表現にコミットすることを少しためらっています。たとえば、_Option<~int>_をnull可能ポインターに折りたたみ、Result<(),~str>をnull可能文字列に折りたたみたい、または_Either<u8,~str>_を1 Wordに折りたたみたい、文字列がアドレス空間の上位256バイトを決して占有できないと仮定します。しばらくの間、Rust enumsのビットパターンは指定されておらず、最適化を実行するためにできるだけ多くのスペースを与えるために、単に言うのが最善であると考えました。

7
barjak