- Published on
Understanding Rust ref keyword
- Authors
- Name
- Bruno Paulino
- @bpaulino0
I'm currently building a native app at work with the Rust programming language (using tauri as my base framework) and I came across this match pattern where I did not want to consume the value bound to my variable. In Rust terms, I wanted to only get a reference to the inner value of a pattern.
This is where the ref keyword is handy. It allow us to extract the inner value of a pattern by borrowing instead of moving. Let's take a look at an example:
fn main() {
let greetings: Option<String> = Some(String::from("hi there"));
// Here we consume the value bound to `greetings`,
// no longer allowing it to be used across the scope.
match greetings {
Some(msg) => println!("{}", msg),
None => println!("Nothing to greet"),
}
// When trying to use `greetings` from this point on...
println!("Greetings? {}", greetings);
// you will get the following compiler error:
// |
// | Some(msg) => println!("{}", msg),
// | --- value partially moved here
// |
// | println!("Greetings? {:?}", greetings);
// | ^^^^^^^^^ value borrowed here after partial move
}
The compiler does a great job at warning you about that move, but it's an error, so it does not let you move forward. To fix that, you can use ref
:
fn main() {
let greetings: Option<String> = Some(String::from("hi there"));
match greetings {
// ref now allows us to bind the inner content of the Option value
// by borrowing instead of move
Some(ref msg) => println!("{}", msg),
None => println!("Nothing to greet"),
}
// This is now allowed. No compiler errors anymore.
println!("Greetings? {:?}", greetings);
}
Binding behind a Mutex guard
One specific case I had was to borrow from a value that was protected by a Mutex and shared across threads. The ref keyword allowed me to borrow this shared value in a safe way.
use std::sync::Mutex;
struct Settings {
api_key: Option<String>,
}
fn main() {
let value = Mutex::new(Settings {
api_key: Some("some-key".into()),
});
// pretend this lock is being acquired on a different thread...
let guard = value.lock().unwrap();
if let Some(ref api_key) = guard.api_key {
println!("got a handle on the api key: {}", api_key);
}
println!("guard still in scope and will be dropped: {:?}", guard.api_key);
}