標準ライブラリの型
(原文)
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 を使用するとこの問題を回避できます。