|
| 1 | +# Clone to satisfy the borrow checker |
| 2 | + |
| 3 | +## Description |
| 4 | + |
| 5 | +The borrow checker prevents Rust users from developing otherwise unsafe code by |
| 6 | +ensuring that either: only one mutable reference exists, or potentially many but |
| 7 | +all immutable references exist. If the code written does not hold true to these |
| 8 | +conditions, this anti-pattern arises when the developer resolves the compiler |
| 9 | +error by cloning the variable. |
| 10 | + |
| 11 | +## Example |
| 12 | + |
| 13 | +```rust |
| 14 | +// define any variable |
| 15 | +let mut x = 5; |
| 16 | + |
| 17 | +// Borrow `x` -- but clone it first |
| 18 | +let y = &mut (x.clone()); |
| 19 | + |
| 20 | +// perform some action on the borrow to prevent rust from optimizing this |
| 21 | +//out of existence |
| 22 | +*y += 1; |
| 23 | + |
| 24 | +// without the x.clone() two lines prior, this line would fail on compile as |
| 25 | +// x has been borrowed |
| 26 | +// thanks to x.clone(), x was never borrowed, and this line will run. |
| 27 | +println!("{}", x); |
| 28 | +``` |
| 29 | + |
| 30 | +## Motivation |
| 31 | + |
| 32 | +It is tempting, particularly for beginners, to use this pattern to resolve |
| 33 | +confusing issues with the borrow checker. However, there are serious |
| 34 | +consequences. Using `.clone()` causes a copy of the data to be made. Any changes |
| 35 | +between the two are not synchronized -- as if two completely separate variables |
| 36 | +exist. |
| 37 | + |
| 38 | +There are special cases -- `Rc<T>` is designed to handle clones intelligently. |
| 39 | +It internally manages exactly one copy of the data, and cloning it will only |
| 40 | +clone the reference. |
| 41 | + |
| 42 | +There is also `Arc<T>` which provides shared ownership of a value of type T |
| 43 | +that is allocated in the heap. Invoking `.clone()` on `Arc` produces a new `Arc` |
| 44 | +instance, which points to the same allocation on the heap as the source `Arc`, |
| 45 | +while increasing a reference count. |
| 46 | + |
| 47 | +In general, clones should be deliberate, with full understanding of the |
| 48 | +consequences. If a clone is used to make a borrow checker error disappear, |
| 49 | +that's a good indication this anti-pattern may be in use. |
| 50 | + |
| 51 | +Even though `.clone()` is an indication of a bad pattern, sometimes |
| 52 | +**it is fine to write inefficient code**, in cases such as when: |
| 53 | + |
| 54 | +- the developer is still new to ownership |
| 55 | +- the code doesn't have great speed or memory constraints |
| 56 | + (like hackathon projects or prototypes) |
| 57 | +- satisfying the borrow checker is really complicated and you prefer to |
| 58 | + optimize readability over performance |
| 59 | + |
| 60 | +If an unnecessary clone is suspected, The [Rust Book's chapter on Ownership](https://doc.rust-lang.org/book/ownership.html) |
| 61 | +should be understood fully before assessing whether the clone is required or not. |
| 62 | + |
| 63 | +Also be sure to always run `cargo clippy` in your project, which will detect some |
| 64 | +cases in which `.clone()` is not necessary, like [1](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone), |
| 65 | +[2](https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy), |
| 66 | +[3](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) or [4](https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref). |
| 67 | + |
| 68 | +## See also |
| 69 | + |
| 70 | +- [`mem::{take(_), replace(_)}` to keep owned values in changed enums](../idioms/mem-replace.md) |
| 71 | +- [`Rc<T>` documentation, which handles .clone() intelligently](http://doc.rust-lang.org/std/rc/) |
| 72 | +- [`Arc<T>` documentation, a thread-safe reference-counting pointer](https://doc.rust-lang.org/std/sync/struct.Arc.html) |
| 73 | +- [Tricks with ownership in Rust](https://web.archive.org/web/20210120233744/https://xion.io/post/code/rust-borrowchk-tricks.html) |
0 commit comments