In the code we looked at above (see Chapter 7/code/lifetimes.rs) the value of n is copied to a new location each time n is assigned via a new let binding or passed as a function argument:
let n = 42u32; let n2 = n; // no move, only a copy of the value n to n2 life(n); // copy of the value n to m fn life(m: u32) -> u32 { let o = m; // copy of the value m to o o }
At a certain moment in the program's execution we would have four memory locations containing the copied value 42, which we could visualize as follows:

Each value disappears (and its memory location is freed) when the lifetime of its corresponding variable ends, which is at the end of the function or code block in which it is defined. Nothing much can go wrong with this Copy behavior, in which the value (its bits) is simply copied to another location on the stack. Many built-in types, like u32 and i64 work like this, and this copy-value behavior is defined in Rust as the Copy trait, which u32 and i64 implement.
You can also implement the Copy trait for your own type, provided all of its fields or items implement Copy.
Let's now look at what happens when we do struct assignments: struct MagicNumber { value: u64 }
Try the following code:
let mag = MagicNumber {value: 42}; let mag2 = mag; let mag3 = mag;
The standard behavior is different, we now get a compiler error:
error[E0382]: use of moved value: `mag`
let mag2 = mag; ---- value moved here let mag3 = mag; ^^^^ value used here after move
When mag was assigned to mag2, the ownership of that value was transferred to mag2--the value was moved. mag doesn't own it anymore, so using mag, for example in a new assignment cannot work, providing the following error:
value used after move
We'll go into more detail in the section Ownership and Borrowing.
Having only one owner of a value is a good thing: then the value can only be changed through one variable! This eliminates a lot of potential bugs.
One way to solve the compiler error is suggested in the note--let MagicNumber implement the Copy trait.
A type that does not implement the Copy trait, as is MagicNumber at this moment, is called non-copyable.
To make MagicNumber copyable, there is one more thing we need to know.
The Clone trait is a supertrait of Copy which states that every structure that implements Clone can duplicate itself. So if a struct implements Copy, it should also implement Clone. The Clone specifies that the following function must be implemented:
fn clone(&self) -> Self;
It takes a reference to the current object (&self) and returns a duplicate of that, which is of course of the same type Self.
Let's now implement Copy for the struct MagicNumber, which contains a field of type u64. This can be done in two ways:
- One way is by explicitly naming the Copy and Clone implementation like this:
impl Copy for MagicNumber {} impl Clone for MagicNumber { fn clone(&self) -> MagicNumber {
*self
} }
- The *self here is the dereferencing operator which says: return the value in the memory location &self points to.
- Or we can annotate the struct with an attribute and let the compiler do the work for us:
#[derive(Copy, Clone)] struct MagicNumber { value: u64 }
Now our previous code is allowed:
let mag2 = mag; let mag3 = mag;
The mag, mag2, and mag3 variables are distinct copies because they have different memory addresses, which we can show as follows (the values shown will differ at each execution):
println!("address mag: {:p}", &mag); // address mag: 0x6ebbcff550 println!("address mag2: {:p}", &mag2); // address mag2: 0x6ebbcff558 println!("address mag3: {:p}", &mag3); // address mag3: 0x6ebbcff568
The &mag instance is the address of the mag value; we have to use :p in the format string, p stands for pointer.
Because MagicNumber now also implements the Clone trait, we can also use the clone() method explicitly to make a copy of mag to a different object mag4, like this:
let mag4 = mag.clone(); println!("address mag4: {:p}", &mag4); // address mag4: 0x7c0053f820
If we want to display the contents of our struct like this:
println!("mag is: {}", mag);
Or:
println!("mag is: {:?}", mag);
We get an error:
error[E0277]: the trait bound `MagicNumber: std::fmt::Display` is not satisfied;
Rust tells us that it doesn't know how to display the struct's value. To let the {:?} version work, which is the debug format-string, MagicNumber has to implement the Debug trait, which we can do by adding a #[derive(Debug)] attribute.
(All three traits can also be combined in: #[derive(Debug, Copy, Clone)]).
Now the last print statement gives us the following output:
mag is: MagicNumber { value: 42 }
The following code snippet shows how to implement the Clone trait for a struct:
// see code in Chapter 7/code/clone.rs: struct Block { number: Box<i32> } impl Clone for Block { fn clone(&self) -> Self { Block{ number: self.number.clone() } } } fn print_block(block: Block) { println!("{:p}: {:?}", block.number, block.number); } fn main() { let block = Block{ number: Box::new(1) }; println!("{:p}: {:?}", block.number, block.number); print_block(block.clone()); }
This prints out the following output:
0x20c5ca23b00: 1 0x20c5ca2cbe0: 1