https://www.snoyman.com/blog/2018/11/rust-crash-course-06-lifetimes-slices
I also blog frequently on the Yesod Web Framework blog, as well as the FP Complete blog.
See a typo? Have a suggestion? Edit this page on Github
We’ve glossed over some details of lifetimes and sequences of values so far. It’s time to dive in and learn about lifetimes and slices correctly.
This post is part of a series based on teaching Rust at FP Complete. If you’re reading this post outside of the blog, you can find links to all posts in the series at the top of the introduction post. You can also subscribe to the RSS feed.
Let’s look at some fairly unsurprising code:
#[derive(Debug)]
struct Person {
name: Option<String>,
age: Option<u32>,
}
fn print_person(person: Person) {
match person.name {
Some(name) => println!("Name is {}", name),
None => println!("No name provided"),
}
match person.age {
Some(age) => println!("Age is {}", age),
None => println!("No age provided"),
}
}
fn main() {
print_person(Person {
name: Some(String::from("Alice")),
age: Some(30),
});
}
Fairly simple, and a nice demonstration of pattern matching. However, let’s throw in one extra line. Try adding this at the beginning of the print_person function:
println!("Full Person value: {:?}", person);
All good. We’re printing the full contents of the Person and then pattern matching. But try adding that line to the end of the function, and you’ll get a compilation error:
error[E0382]: use of partially moved value: `person`
--> main.rs:18:41
|
9 | Some(name) => println!("Name is {}", name),
| ---- value moved here
...
18 | println!("Full Person value: {:?}", person);
| ^^^^^^ value used here after move
|
= note: move occurs because the value has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
NOTE This is an error with the Rust compiler I’m using, 1.30.1. However, there are plans in place to improve this situation.
The problem is that we’ve consumed a part of the person value, and therefore cannot display it. We can fix that by setting it again. Let’s make the person argument mutable, and then fill in the moved person.name with a default None value:
fn print_person(mut person: Person) {
match person.name {
Some(name) => println!("Name is {}", name),
None => println!("No name provided"),
}
match person.age {
Some(age) => println!("Age is {}", age),
None => println!("No age provided"),
}
person.name = None;
println!("Full Person value: {:?}", person);
}
That compiles, but now the output is confusingly:
Name is Alice
Age is 30
Full Person value: Person { name: None, age: Some(30) }
Notice how the name in the last line in None, when ideally it should be Some(Alice). We can do better, by returning the name from the match:
person.name = match person.name {
Some(name) => {
println!("Name is {}", name);
Some(name)
},
None => {
println!("No name provided");
None
}
};