Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

借用チェッカーを満たすためのクローン

説明

借用チェッカーは、可変参照が1つだけ存在するか、あるいは複数存在し得るもののすべて不変参照であるかのいずれかを保証することで、Rust ユーザーが本来なら安全でないコードを開発することを防ぎます。書かれたコードがこれらの条件を満たしていない場合に、開発者が変数をクローンすることでコンパイラエラーを解決すると、このアンチパターンが発生します。

#![allow(unused)]
fn main() {
// 任意の変数を定義する
let mut x = 5;

// `x` を借用する -- ただし、まずクローンする
let y = &mut (x.clone());

// 2行前の x.clone() がなければ、この行はコンパイル時に失敗する。
// x が借用されているため
// x.clone() のおかげで、x は一度も借用されず、この行は実行される。
println!("{x}");

// Rust がこれを最適化で消し去らないように、借用に対して
//何らかの操作を行う
*y += 1;
}

動機

特に初心者にとって、借用チェッカーに関するわかりにくい問題を解決するために、このパターンを使いたくなることがあります。しかし、重大な影響があります。.clone() を使うと、データのコピーが作成されます。その2つの間の変更は同期されません – まるで完全に別々の変数が2つ存在するかのようです。

特殊なケースもあります – Rc<T> はクローンを賢く扱うように設計されています。内部ではデータのコピーを厳密に1つだけ管理します。Rc に対して .clone() を呼び出すと、新しい Rc インスタンスが生成されます。これは参照カウントを増やしつつ、元の Rc と同じデータを指します。同じことは、Rc のスレッドセーフな対応物である Arc にも当てはまります。

一般に、クローンはその影響を十分に理解したうえで、意図的に行うべきです。借用チェッカーのエラーを消すためにクローンが使われているなら、このアンチパターンが使われている可能性を示す良い兆候です。

.clone() は悪いパターンを示すものですが、次のような場合には、非効率なコードを書いても問題ないこともあります。

  • 開発者が所有権にまだ慣れていない
  • コードに速度やメモリの厳しい制約がない(ハッカソンのプロジェクトやプロトタイプなど)
  • 借用チェッカーを満たすのが非常に複雑で、性能よりも可読性の最適化を優先したい

不要なクローンが疑われる場合は、そのクローンが必要かどうかを評価する前に、Rust Book の所有権に関する章を十分に理解しておくべきです。

また、プロジェクトでは必ず cargo clippy を実行してください。これにより、.clone() が不要ないくつかのケースを検出できます。

関連項目