blob: 093ffa33a336962763a6239ec3721736e6b0a177 [file] [view]
# Clone and Copy
When dealing with resources, the default behavior is to transfer them during
assignments or function calls. However, sometimes we need to make a
copy of the resource as well.
The [`Clone`][clone] trait helps us do exactly this. Most commonly, we can
use the `.clone()` method defined by the `Clone` trait.
## Copy: Implicit Cloning
The [`Copy`][copy] trait allows a type to be duplicated simply by copying bits,
with no additional logic required. When a type implements `Copy`, assignments
and function calls will implicitly copy the value instead of moving it.
**Important:** `Copy` requires `Clone` - any type that implements `Copy` must
also implement `Clone`. This is because `Copy` is defined as a subtrait:
`trait Copy: Clone {}`. The `Clone` implementation for `Copy` types simply
copies the bits.
Not all types can implement `Copy`. A type can only be `Copy` if:
- All of its components are `Copy`
- It doesn't manage external resources (like heap memory, file handles, etc.)
```rust,editable
// A unit struct without resources
// Note: Copy requires Clone, so we must derive both
#[derive(Debug, Clone, Copy)]
struct Unit;
// A tuple struct with resources that implements the `Clone` trait
// This CANNOT be Copy because Box<T> is not Copy
#[derive(Clone, Debug)]
struct Pair(Box<i32>, Box<i32>);
fn main() {
// Instantiate `Unit`
let unit = Unit;
// Copy `Unit` - this is an implicit copy, not a move!
// Because Unit implements Copy, the value is duplicated automatically
let copied_unit = unit;
// Both `Unit`s can be used independently
println!("original: {:?}", unit);
println!("copy: {:?}", copied_unit);
// Instantiate `Pair`
let pair = Pair(Box::new(1), Box::new(2));
println!("original: {:?}", pair);
// Move `pair` into `moved_pair`, moves resources
// Pair does not implement Copy, so this is a move
let moved_pair = pair;
println!("moved: {:?}", moved_pair);
// Error! `pair` has lost its resources
//println!("original: {:?}", pair);
// TODO ^ Try uncommenting this line
// Clone `moved_pair` into `cloned_pair` (resources are included)
// Unlike Copy, Clone is explicit - we must call .clone()
let cloned_pair = moved_pair.clone();
// Drop the moved original pair using std::mem::drop
drop(moved_pair);
// Error! `moved_pair` has been dropped
//println!("moved and dropped: {:?}", moved_pair);
// TODO ^ Try uncommenting this line
// The result from .clone() can still be used!
println!("clone: {:?}", cloned_pair);
}
```
[clone]: https://doc.rust-lang.org/std/clone/trait.Clone.html
[copy]: https://doc.rust-lang.org/std/marker/trait.Copy.html