Converting from Option<String> to Option<&str>
As of Rust 1.40, the standard library has Option::as_deref
to do this:
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_deref().unwrap_or("default string");
}
You can use as_ref()
and map()
to transform an Option<String>
into an Option<&str>
.
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map(|x| &**x).unwrap_or("default string");
}
First, as_ref()
implicitly takes a reference on opt
, giving an &Option<String>
(because as_ref()
takes &self
, i.e. it receives a reference), and turns it into an Option<&String>
. Then we use map
to convert it to an Option<&str>
. Here's what &**x
does: the rightmost *
(which is evaluated first) simply dereferences the &String
, giving a String
lvalue. Then, the leftmost *
actually invokes the Deref
trait, because String
implements Deref<Target=str>
, giving us a str
lvalue. Finally, the &
takes the address of the str
lvalue, giving us a &str
.
You can simplify this a bit further by using map_or
to combine map
and unwrap_or
in a single operation:
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", |x| &**x);
}
If &**x
looks too magical to you, you can write String::as_str
instead:
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", String::as_str);
}
or String::as_ref
(from the AsRef
trait, which is in the prelude):
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", String::as_ref);
}
or String::deref
(though you need to import the Deref
trait too):
use std::ops::Deref;
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.as_ref().map_or("default string", String::deref);
}
For either of these to work, you need to keep an owner for the Option<String>
as long as the Option<&str>
or unwrapped &str
needs to remain available. If that's too complicated, you could use Cow
.
use std::borrow::Cow::{Borrowed, Owned};
fn main() {
let opt: Option<String> = Some("some value".to_owned());
let value = opt.map_or(Borrowed("default string"), |x| Owned(x));
}
A nicer way could be to implement this generically for T: Deref
:
use std::ops::Deref;
trait OptionDeref<T: Deref> {
fn as_deref(&self) -> Option<&T::Target>;
}
impl<T: Deref> OptionDeref<T> for Option<T> {
fn as_deref(&self) -> Option<&T::Target> {
self.as_ref().map(Deref::deref)
}
}
which effectively generalizes as_ref
.