Borrowing
References in Rust are explicit at both the caller and the callee. Our simple "do something" example with a reference works:
fn do_something(s: &String) { // Something happens here } fn main() { let s = "Hello".to_string(); do_something(&s); println!("{s}"); }
Contrast this with C++ in which you don't specify the
&
on the caller. It's more typing, but you can't accidentally copy your data when the function signature changes.
If you want to allow the function to change/mutate the data, you need to mutably borrow it:
fn do_something(s: &mut String) { // Something happens here *s += " World"; } fn main() { let mut s = "Hello".to_string(); do_something(&mut s); println!("{s}"); }
Notice that this is even more pedantic: you have to make s
mutable before it can be borrowed mutably. And then you have to explicitly mark the borrow &mut
. There's no escaping it---Rust makes you specify your intent when you lend the data to another funciton.
Borrowing Strings
Strings have a special case. A string contains a buffer of characters, and you can immutably refer to the characters as &str
---a static string. So this also works:
fn do_something(s: &str) { // Something happens here } fn main() { let s = "Hello".to_string(); do_something(&s); println!("{s}"); }
As we saw in the strings section, you can't modify an str
buffer---but if all you need to do is print or use the string in a formatting expression (etc.), it can be quicker to just pass the reference.