標準ライブラリの型
(原文)
Box
、[Vec
]、Option
、Result
、そして Rc
/Arc
のような、よく使われる標準ライブラリの型のドキュメントを読むことは、パフォーマンスを向上させるのに使える面白い関数を見つけることに繋がります。
また、Mutex
、RwLock
、Condvar
、そして Once
のような、パフォーマンス向上という視点で他の標準ライブラリの型の代替となり得る型についても知っておくべきでしょう。
Box
Box::default()
という式は Box::new(T::default())
と同じ効果を持ちますが、コンパイラがそれをスタック上に構築しコピーするのではなく、ヒープ上に直接値を作成できるという点で高速になる場合があります。
Vec
Vec::remove
は特定のインデックスの要素を削除し後ろにある要素を 1 つずつ左にシフトさせます。計算量は O(n) です。対して、Vec::swap_remove
は特定のインデックスの要素を最後の要素と入れ替えつつ削除します。これは順序を保持しませんが、計算量は O(1) です。
Vec::retain
は Vec
から複数のアイテムを効果的に削除します。String
、HashSet
、そして HashMap
のような他のコレクション型にも同様のメソッドがあります。
Option
と Result
Option::ok_or
は Option
を Result
に変換します。もし Option
の値が None
だった場合には、ok_or
の引数が err
のパラメータとして渡されます。err
は先行評価されます。もしそのコストが大きい場合には代わりに Option::ok_or_else
を使用して、クロージャを通してそのエラーの値を遅延評価するようにすべきです。例えばこれは:
#![allow(unused)] fn main() { fn expensive() {} let o: Option<u32> = None; let r = o.ok_or(expensive()); // 常に `expensive()` として評価される }
このように変更すべきです:
#![allow(unused)] fn main() { fn expensive() {} let o: Option<u32> = None; let r = o.ok_or_else(|| expensive()); // 必要なときだけ `expensive()` として評価される }
Option::map_or
、Option::unwrap_or
、Result::or
、Result::map_or
、そして Result::unwrap_or
のような、似たような類似メソッドが他にもあります。
Rc
/Arc
Rc::make_mut
/Arc::make_mut
は "clone-on-write" なセマンティクスを提供し、Rc
/Arc
への可変参照を作成します。もし参照カウントが 1 より大きい場合には、所有権が一意であることを確保するために中の値をクローンします。そうでなければ、つまり参照カウントが 1 であれば、元の値を変更します。これらのメソッドは頻繁には必要になりませんが、場合によってはとても役に立ちます。
Mutex
、RwLock
、Condvar
、そして Once
parking_lot
クレートは上記の標準ライブラリの同期的な型よりも小さく、高速で、フレキシブルな代替実装を提供します。parking_lot
にある型の API とセマンティクスは標準ライブラリのそれらと似ていますが同じものではありません。
もし parking_lot
の型を広く使おうとした場合、いくつかの場所で間違って標準ライブラリの型を使ってしまう、ということが容易に起こり得ます。clippy
を使用するとこの問題を回避できます。