Lifetimes
Sorting an immutable collection of strings
Let us assume that we want to write a function which sorts an immutable collection of String elements. Here, "immutable" means that we cannot modify either the strings or the collection itself. We will have to return a Vec containing the result.
Exercise 2.a: write a function sorted which takes a reference to a slice of String instances and return a Vec<String> with the sorted strings.
The function will have the following signature:
#![allow(unused)] fn main() { fn sorted(names: &[String]) -> Vec<String> { todo!() // Write the code here } }
You can use the following constructs to help you to so:
vec![]creates an emptyVec(the type of the elements will be deduced from the context).- If
sis aString(or a&String),s.clone()will produce a newStringwith the same content ass. - You can iterate over the content of a slice
namesof type&[String]withfor name in names { … }.namewill have type&Stringwithin the loop. - You can use
.sort()on a mutable slice: it will sort your elements in the natural order.
You can test your function with the following main program:
fn main() { let people = [String::from("John Doe"), String::from("Jane Eyre"), String::from("Jane Doe")]; let in_order = sorted(&people); for n in in_order { println!("- {n}"); } }
This should print "Jane Doe", "Jane Eyre", and "John Doe" in order.
Avoiding cloning the strings
While the previous program works, you had to clone the immutable strings. This is unfortunate as this consumes more memory. Why not work directly with a Vec of &String and sort it?
Exercise 2.b: modify your sorted function so that it returns a Vec<&String> instead of a Vec<String>.
Note that .sort() will work on a collection of &String: it will sort them the same way it sorted String elements.
Testing the guarantees of lifetimes
The signature of your sorted function is:
#![allow(unused)] fn main() { fn sorted(names: &[String]) -> Vec<&String> }
Since you have not indicated any explicit lifetime (remember, lifetimes start with a single tick character '), lifetimes elision kicked in: the lifetime of the &[String] slice was copied over the &String elements inside the Vec.
It means that the result of sorted() cannot live longer than its argument names.
Exercise 2.c: experiment with the following modified main program, which will not compile, and make sure you understand why the compiler is telling you that you cannot store the output of sorted(&people) into in_order. Note how it prevents you from referencing strings that have been destroyed when people went out of scope. You would not have had any such guarantee in C.
fn main() { let in_order = { let people = [String::from("John Doe"), String::from("Jane Eyre"), String::from("Jane Doe")]; sorted(&people) }; for n in in_order { println!("- {n}"); } }