diff --git a/404.html b/404.html index c930a3f..f985642 100644 --- a/404.html +++ b/404.html @@ -97,7 +97,7 @@ diff --git a/additional_resources/design-principles.html b/additional_resources/design-principles.html index d6832ae..dab25e6 100644 --- a/additional_resources/design-principles.html +++ b/additional_resources/design-principles.html @@ -95,7 +95,7 @@ diff --git a/additional_resources/index.html b/additional_resources/index.html index 31729c0..e66d889 100644 --- a/additional_resources/index.html +++ b/additional_resources/index.html @@ -95,7 +95,7 @@ diff --git a/anti_patterns/borrow_clone.html b/anti_patterns/borrow_clone.html new file mode 100644 index 0000000..3121003 --- /dev/null +++ b/anti_patterns/borrow_clone.html @@ -0,0 +1,303 @@ + + + + + + Clone to satisfy the borrow checker - Rust Design Patterns + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + +
+
+

Clone to satisfy the borrow checker

+

Description

+

The borrow checker prevents Rust users from developing otherwise unsafe code by +ensuring that either: only one mutable reference exists, or potentially many but +all immutable references exist. If the code written does not hold true to these +conditions, this anti-pattern arises when the developer resolves the compiler +error by cloning the variable.

+

Example

+

+#![allow(unused)]
+fn main() {
+// define any variable
+let mut x = 5;
+
+// Borrow `x` -- but clone it first
+let y = &mut (x.clone());
+
+// perform some action on the borrow to prevent rust from optimizing this
+//out of existence
+*y += 1;
+
+// without the x.clone() two lines prior, this line would fail on compile as
+// x has been borrowed
+// thanks to x.clone(), x was never borrowed, and this line will run.
+println!("{}", x);
+}
+
+

Motivation

+

It is tempting, particularly for beginners, to use this pattern to resolve +confusing issues with the borrow checker. However, there are serious +consequences. Using .clone() causes a copy of the data to be made. Any changes +between the two are not synchronized -- as if two completely separate variables +exist.

+

There are special cases -- Rc<T> is designed to handle clones intelligently. +It internally manages exactly one copy of the data, and cloning it will only +clone the reference.

+

There is also Arc<T> which provides shared ownership of a value of type T +that is allocated in the heap. Invoking .clone() on Arc produces a new Arc +instance, which points to the same allocation on the heap as the source Arc, +while increasing a reference count.

+

In general, clones should be deliberate, with full understanding of the +consequences. If a clone is used to make a borrow checker error disappear, +that's a good indication this anti-pattern may be in use.

+

Even though .clone() is an indication of a bad pattern, sometimes +it is fine to write inefficient code, in cases such as when:

+
    +
  • the developer is still new to ownership
  • +
  • the code doesn't have great speed or memory constraints +(like hackathon projects or prototypes)
  • +
  • satisfying the borrow checker is really complicated and you prefer to +optimize readability over performance
  • +
+

If an unnecessary clone is suspected, The Rust Book's chapter on Ownership +should be understood fully before assessing whether the clone is required or not.

+

Also be sure to always run cargo clippy in your project, which will detect some +cases in which .clone() is not necessary, like 1, +2, +3 or 4.

+

See also

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/anti_patterns/deny-warnings.html b/anti_patterns/deny-warnings.html index 93004ea..54869cb 100644 --- a/anti_patterns/deny-warnings.html +++ b/anti_patterns/deny-warnings.html @@ -95,7 +95,7 @@ @@ -255,7 +255,7 @@ certain that there will be more deprecated APIs in the future.