In older versions of Rust, match
would assume that you want to move what is matched. But sometimes, that’s not what you wanted. For example:
let robot_name = &Some(String::from("Bors"));
match robot_name {
Some(name) => println!("Found a name: {}", name),
None => (),
}
println!("robot_name is: {:?}", robot_name);
Here, robot_name
is a &Option<String>
. Rust would then complain that Some(name)
doesn’t match up with &Option<T>
, so you’d have to write this:
let robot_name = &Some(String::from("Bors"));
match robot_name {
&Some(name) => println!("Found a name: {}", name),
None => (),
}
println!("robot_name is: {:?}", robot_name);
Next, Rust would complain that name is trying to move the String
out of the option, but because it’s a reference to an option, it’s borrowed, and so can’t be moved out of. This is where the ref
keyword comes into play:
let robot_name = &Some(String::from("Bors"));
match robot_name {
&Some(ref name) => println!("Found a name: {}", name),
None => (),
}
println!("robot_name is: {:?}", robot_name);
The ref
keyword is like the opposite of &
in patterns; this says “please bind name
* to be a &String
, don’t try to move it out." In other words, the &
in &Some
is matching against a reference, but ref creates a reference. ref mut
is like ref
, but for mutable references.
Anyway, today’s Rust doesn’t work like this. If you try to match on something borrowed, then all of the bindings you create will attempt to borrow as well. This means that the original code works as you’d expect.
Because Rust is backwards compatible, we couldn’t remove ref and ref mut
, and they’re sometimes useful in obscure situations, where you want to partially borrow part of a struct
as mutable and another part as immutable. But you may see them in older Rust code, so knowing what they do is still useful.