- Published on
Rust Practices with Rustlings - Lifetimes
Chapter 16 - Lifetimes
Exercise 1
// The Rust compiler needs to know how to check whether supplied references are
// valid, so that it can let the programmer know if a reference is at risk of
// going out of scope before it is used. Remember, references are borrows and do
// not own their own data. What if their owner goes out of scope?
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("The longest string is '{}'", result);
}
Because the return type of longest
is a reference to one of the parameters, x or y, so the lifetime of the return value is related to the lifetime of the parameters.
The Rust compiler can’t tell whether the reference being returned refers to x or y, so we need to do that by lifetime annotations.
fn longest<'a'>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
Exercise 2
// So if the compiler is just validating the references passed to the annotated
// parameters and the return type, what do we need to change?
//
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is '{}'", result);
}
The lifetime of longest function is the same as the lifetime of the smaller of the two parameters, here is string 2.
So we have 2 ways to achive the requirement:
- Make the string2 live longer, the same as the println! statement
fn main() {
let string1 = String::from("long string is long");
let string2 = String::from("xyz");
let result;
{
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is '{}'", result);
}
- Or move the println statement into the inner scope where the string2 still valid
fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
println!("The longest string is '{}'", result);
}
}
Exercise 3
// Lifetimes are also needed when structs hold references.
struct Book {
author: & str,
title: & str,
}
fn main() {
let name = String::from("Jill Smith");
let title = String::from("Fish Flying");
let book = Book { author: &name, title: &title };
println!("{} by {}", book.title, book.author);
}
The same as with function, we need to annotate the lifetime of the struct
struct Book<'a> {
author: &'a str,
title: &'a str,
}
Conclusion
The 16th chapter of Rustlings - Lifetimes ends here.
TIL:
- What is lifetimes and how to annotate them
Thanks for reading and please add comments below if you have any questions