Add new section on trait bounds.
This commit is contained in:
111
book/src/04_traits/11_clone.md
Normal file
111
book/src/04_traits/11_clone.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Copying values, pt. 1
|
||||
|
||||
In the previous chapter we introduced ownership and borrowing.
|
||||
We stated, in particular, that:
|
||||
|
||||
- Every value in Rust has a single owner at any given time.
|
||||
- When a function takes ownership of a value ("it consumes it"), the caller can't use that value anymore.
|
||||
|
||||
These restrictions can be somewhat limiting.
|
||||
Sometimes we might have to call a function that takes ownership of a value, but we still need to use
|
||||
that value afterward.
|
||||
|
||||
```rust
|
||||
fn consumer(s: String) { /* */ }
|
||||
|
||||
fn example() {
|
||||
let mut s = String::from("hello");
|
||||
consumer(s);
|
||||
s.push_str(", world!"); // error: value borrowed here after move
|
||||
}
|
||||
```
|
||||
|
||||
That's where `Clone` comes in.
|
||||
|
||||
## `Clone`
|
||||
|
||||
`Clone` is a trait defined in Rust's standard library:
|
||||
|
||||
```rust
|
||||
pub trait Clone {
|
||||
fn clone(&self) -> Self;
|
||||
}
|
||||
```
|
||||
|
||||
Its method, `clone`, takes a reference to `self` and returns a new **owned** instance of the same type.
|
||||
|
||||
## In action
|
||||
|
||||
Going back to the example above, we can use `clone` to create a new `String` instance before calling `consumer`:
|
||||
|
||||
```rust
|
||||
fn consumer(s: String) { /* */ }
|
||||
|
||||
fn example() {
|
||||
let mut s = String::from("hello");
|
||||
let t = s.clone();
|
||||
consumer(t);
|
||||
s.push_str(", world!"); // no error
|
||||
}
|
||||
```
|
||||
|
||||
Instead of giving ownership of `s` to `consumer`, we create a new `String` (by cloning `s`) and give
|
||||
that to `consumer` instead.
|
||||
`s` remains valid and usable after the call to `consumer`.
|
||||
|
||||
## In memory
|
||||
|
||||
Let's look at what happened in memory in the example above.
|
||||
When `let mut s: String::from("hello");` is executed, the memory looks like this:
|
||||
|
||||
```text
|
||||
s
|
||||
+---------+--------+----------+
|
||||
Stack | pointer | length | capacity |
|
||||
| | | 5 | 5 |
|
||||
+--|------+--------+----------+
|
||||
|
|
||||
|
|
||||
v
|
||||
+---+---+---+---+---+
|
||||
Heap: | H | e | l | l | o |
|
||||
+---+---+---+---+---+
|
||||
```
|
||||
|
||||
When `let t = s.clone()` is executed, a whole new region is allocated on the heap to store a copy of the data:
|
||||
|
||||
```text
|
||||
s t
|
||||
+---------+--------+----------+ +---------+--------+----------+
|
||||
Stack | pointer | length | capacity | | pointer | length | capacity |
|
||||
| | | 5 | 5 | | | | 5 | 5 |
|
||||
+--|------+--------+----------+ +--|------+--------+----------+
|
||||
| |
|
||||
| |
|
||||
v v
|
||||
+---+---+---+---+---+ +---+---+---+---+---+
|
||||
Heap: | H | e | l | l | o | | H | e | l | l | o |
|
||||
+---+---+---+---+---+ +---+---+---+---+---+
|
||||
```
|
||||
|
||||
If you're coming from a language like Java, you can think of `clone` as a way to create a deep copy of an object.
|
||||
|
||||
## Implementing `Clone`
|
||||
|
||||
To make a type `Clone`-able, we have to implement the `Clone` trait for it.
|
||||
You almost always implement `Clone` by deriving it:
|
||||
|
||||
```rust
|
||||
#[derive(Clone)]
|
||||
struct MyType {
|
||||
// fields
|
||||
}
|
||||
```
|
||||
|
||||
The compiler implements `Clone` for `MyType` as you would expect: it clones each field of `MyType` individually and
|
||||
then constructs a new `MyType` instance using the cloned fields.
|
||||
Remember that you can use `cargo expand` (or your IDE) to explore the code generated by `derive` macros.
|
||||
|
||||
## References
|
||||
|
||||
- The exercise for this section is located in `exercises/04_traits/10_clone`
|
||||
Reference in New Issue
Block a user