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 trait helps us do exactly this. Most commonly, we can
use the .clone() method defined by the Clone trait.
The 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:
Copy// 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);
}