項目20:過剰な最適化の誘惑を退けよう
LT;DR
しかし、まずは利便性・保守性に焦点を当てて パフォーマンスが本当に重要な場合にだけ、最適化するようにしよう
Rc や Arc を用いると、値を複数箇所で共有して所有できる
加えてミュータブルな操作が必要となる場合は、内部可変性 を実現する RefCell や Mutex を組み合わせると良い e.g. RefCell<Rc<T>>、Mutex<Arc<T>>
hr.icon
データ構造とメモリ確保
一方、参照を用いるとコードが扱いづらくなるというデメリットもある
これは、フィールドを 参照 で保持するデータ構造でよく現れる code:rs
pub struct Tlv<'a> {
pub type_code: u8,
}
特にインスタンスを引き回す場合、面倒なことになる
code:rs
pub struct Tlv {
pub type_code: u8,
pub value: Vec<u8>,
}
大きくて悪いコピーなんて怖くない
∵ コピーとメモリ確保が発生していることが明確になるため
e.g.
.to_vec や .clone などのメソッド呼び出し
Box::new 関数の呼び出し
しかし、明示的になっているからといって、最適化 して取り除く理由にはならない 特に、最適化で利便性が犠牲になる場合は、まずは使いやすさに焦点を当てて「パフォーマンスが本当に重要な場合にだけ、最適化するようにしよう」
ベンチマーク 測定の結果、コピーを減らすことで改善できる場合だけにすべき とはいえ、2 つ覚えておくことがある
1. 「一般に」コピーは明示的に行われる
ただし、「Copy トレイトはビット単位のコピーが有効で高速である場合でのみ実装しよう」
e.g. 追加データを持たない enum 型
2. alloc を利用できる no_std な ビルドターゲット を選択すると、no_std の制約を回避しつつ、使いやすさや再利用性の高い開発が可能になる 再利用性の高い
∵ no_std の方がどんな環境下でも実行できるため
データ構造がフィールドを所有すると、変更があった時にコピーをすべて同期して更新する必要がある
この問題はスマートポインタを用いて、単一所有から共有所有に移行することで回避できる
例えば Rc や Arc は 参照カウンタ を用いて共有所有を実現する 一般的に Rc<RefCell<T>> のように用いる
一般的に Arc<Mutex<T>>
スマートポインタを 最後の手段 として使う必要はない つまり、複雑に絡み合った参照の生存期間を扱う代わりに、スマートポインタを設計に取り入れることは 負けを認める ことではない むしろ、「スマートポインタを使った方が簡潔で、保守しやすく、使いやすい設計になる場合もある」