In Rust, every value has an owner responsible for cleanup when the value’s lifetime ends. A lifetime is the period during which accessing a value is valid. When a value goes out of scope, the compiler arranges for its destructor to run; ordinary Rust code usually does not call destructors directly. Ownership does not give a binding exclusive permission to access its value: other code can borrow it. section 4.0 section 4.3
An owner can change without the data physically moving. Assignment, passing a value into a function, and returning it from a function can all transfer ownership. After a move, the previous binding cannot be used to access that value. section 4.1.1 section 4.4
error[E0382]: use of moved value: `sat_a` --> code/ch4-check-sats-2.rs:26:31 | | let a_status = check_status(sat_a); | ----- value moved here ... | let a_status = check_status(sat_a); | ^^^^^ value used here after move | = note: move occurs because `sat_a` has type `CubeSat`, = which does not implement the `Copy` trait ... #1 error: aborting due to 3 previous errors
The compiler marks the first call as the move and rejects the second use of `sat_a`. The error also notes that `CubeSat` does not implement `Copy`. section 4.1.1
One way to make the satellite available again is to return it. A `check_status(sat_id: CubeSat) -> CubeSat` function receives ownership as an argument, prints the status, and returns `sat_id`. The caller binds that returned value to `sat_a`, allowing another status check later. This works, but passing ownership back and forth is not always the simplest design. section 4.4
Listing 4.7 Returning ownership back to the original scope
#![allow(unused_variables)]
#[derive(Debug)]
struct CubeSat {
id: u64,
}
#[derive(Debug)]
enum StatusMessage {
Ok,
}
fn check_status(sat_id: CubeSat) -> CubeSat {
println!("{:?}: {:?}", sat_id, StatusMessage::Ok);
sat_id
}
fn main () {
let sat_a = CubeSat { id: 0 };
let sat_b = CubeSat { id: 1 };
let sat_c = CubeSat { id: 2 };
let sat_a = check_status(sat_a); #1
let sat_b = check_status(sat_b);
let sat_c = check_status(sat_c);
// "waiting" ...
let sat_a = check_status(sat_a);
let sat_b = check_status(sat_b);
let sat_c = check_status(sat_c);
}
Follow `sat_a` through two calls: each call takes ownership, and each return gives the caller a value it can bind again. section 4.4
When an ownership move makes later code awkward, choose a design that matches the access needed:
- Use a reference when the function needs access rather than full ownership. section 4.5
- Duplicate the value where appropriate; `Clone` and `Copy` are ways to do so. section 4.6
- Shorten how long values stay around, or use a type designed to help with movement issues. section 4.5
The cleanup responsibility also constrains lifetimes: a value cannot outlive its owner. Custom cleanup can be supplied by implementing `Drop`, whose `drop(&mut self)` method performs wind-up work. That is generally unnecessary for ordinary values; the compiler inserts the usual cleanup calls. section 4.3





