Giving references to functions
See this chapter on YouTube: immutable references and mutable references
References are very useful for functions. The rule in Rust on values is: a value can only have one owner.
This code will not work:
fn print_country(country_name: String) { println!("{}", country_name); } fn main() { let country = String::from("Austria"); print_country(country); // We print "Austria" print_country(country); // ⚠️ That was fun, let's do it again! }
It does not work because country is destroyed. Here's how:
- Step 1: We create the
Stringcalledcountry.countryis the owner. - Step 2: We give
countrytoprint_country.print_countrydoesn't have an->, so it doesn't return anything. Afterprint_countryfinishes, ourStringis now dead. - Step 3: We try to give
countrytoprint_country, but we already did that. We don't havecountryto give anymore.
We can make print_country give the String back, but it is a bit awkward.
fn print_country(country_name: String) -> String { println!("{}", country_name); country_name // return it here } fn main() { let country = String::from("Austria"); let country = print_country(country); // we have to use let here now to get the String back print_country(country); }
Now it prints:
Austria
Austria
The much better way to fix this is by adding &.
fn print_country(country_name: &String) { println!("{}", country_name); } fn main() { let country = String::from("Austria"); print_country(&country); // We print "Austria" print_country(&country); // That was fun, let's do it again! }
Now print_country() is a function that takes a reference to a String: a &String. Also, we give it a reference to country by writing &country. This says "you can look at it, but I will keep it".
Now let's do something similar with a mutable reference. Here is an example of a function that uses a mutable variable.
fn add_hungary(country_name: &mut String) { // first we say that the function takes a mutable reference country_name.push_str("-Hungary"); // push_str() adds a &str to a String println!("Now it says: {}", country_name); } fn main() { let mut country = String::from("Austria"); add_hungary(&mut country); // we also need to give it a mutable reference. }
This prints Now it says: Austria-Hungary.
So to conclude:
fn function_name(variable: String)takes aStringand owns it. If it doesn't return anything, then the variable dies inside the function.fn function_name(variable: &String)borrows aStringand can look at itfn function_name(variable: &mut String)borrows aStringand can change it
Here is an example that looks like a mutable reference, but it is different.
fn main() { let country = String::from("Austria"); // country is not mutable, but we are going to print Austria-Hungary. How? adds_hungary(country); } fn adds_hungary(mut country: String) { // Here's how: adds_hungary takes the String and declares it mutable! country.push_str("-Hungary"); println!("{}", country); }
How is this possible? It is because mut country is not a reference: adds_hungary owns country now. (Remember, it takes String and not &String). The moment you call adds_hungary, it becomes the full owner. country has nothing to do with String::from("Austria") anymore. So adds_hungary can take country as mutable, and it is perfectly safe to do so.
Remember our employee Powerpoint and manager situation above? In this situation it is like the employee just giving his whole computer to the manager. The employee won't ever touch it again, so the manager can do anything he wants to it.