112 lines
3.4 KiB
Markdown
112 lines
3.4 KiB
Markdown
|
# 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 s
|
||
|
+---------+--------+----------+ +---------+--------+----------+
|
||
|
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`
|