Converting from Option<String> to Option<&str> - rust

Very often I have obtained an Option<String> from a calculation, and I would like to either use this value or a default hardcoded value.
This would be trivial with an integer:
let opt: Option<i32> = Some(3);
let value = opt.unwrap_or(0); // 0 being the default
But with a String and a &str, the compiler complains about mismatched types:
let opt: Option<String> = Some("some value".to_owned());
let value = opt.unwrap_or("default string");
The exact error here is:
error[E0308]: mismatched types
--> src/main.rs:4:31
|
4 | let value = opt.unwrap_or("default string");
| ^^^^^^^^^^^^^^^^
| |
| expected struct `std::string::String`, found reference
| help: try using a conversion method: `"default string".to_string()`
|
= note: expected type `std::string::String`
found type `&'static str`
One option is to convert the string slice into an owned String, as suggested by rustc:
let value = opt.unwrap_or("default string".to_string());
But this causes an allocation, which is undesirable when I want to immediately convert the result back to a string slice, as in this call to Regex::new():
let rx: Regex = Regex::new(&opt.unwrap_or("default string".to_string()));
I would rather convert the Option<String> to an Option<&str> to avoid this allocation.
What is the idiomatic way to write this?

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");
}
See also:
How can I iterate on an Option<Vec<_>>?

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.

Although I love Veedrac's answer (I used it), if you need it at just one point and you would like something that is expressive you can use as_ref(), map and String::as_str chain:
let opt: Option<String> = Some("some value".to_string());
assert_eq!(Some("some value"), opt.as_ref().map(String::as_str));

Here's one way you can do it. Keep in mind that you have to keep the original String around, otherwise what would the &str be a slice into?
let opt = Some(String::from("test")); // kept around
let unwrapped: &str = match opt.as_ref() {
Some(s) => s, // deref coercion
None => "default",
};
playpen

Related

Temporarily cache owned value between iterator adapters

I'd like to know if there's a way to cache an owned value between iterator adapters, so that adapters later in the chain can reference it.
(Or if there's another way to allow later adapters to reference an owned value that lives inside the iterator chain.)
To illustrate what I mean, let's look at this (contrived) example:
I have a function that returns a String, which is called in an Iterator map() adapter, yielding an iterator over Strings. I'd like to get an iterator over the chars() in those Strings, but the chars() method requires a string slice, meaning a reference.
Is this possible to do, without first collecting the Strings?
Here's a minimal example that of course fails:
fn greet(c: &str) -> String {
"Hello, ".to_owned() + c
}
fn main() {
let names = ["Martin", "Helena", "Ingrid", "Joseph"];
let iterator = names.into_iter().map(greet);
let fails = iterator.flat_map(<str>::chars);
}
Playground
Using a closure instead of <str>::chars - |s| s.chars() - does of course not work either. It makes the types match, but breaks lifetimes.
Edit (2022-10-03): In response to the comments, here's some pseudocode of what I have in mind, but with incorrect lifetimes:
struct IteratorCache<'a, T, I>{
item : Option<T>,
inner : I,
_p : core::marker::PhantomData<&'a T>
}
impl<'a, T, I> Iterator for IteratorCache<'a, T,I>
where I: Iterator<Item=T>
{
type Item=&'a T;
fn next(&mut self) -> Option<&'a T> {
self.item = self.inner.next();
if let Some(x) = &self.item {
Some(&x)
} else {
None
}
}
}
The idea would be that the reference could stay valid until the next call to next(). However I don't know if this can be expressed with the function signature of the Iterator trait. (Or if this can be expressed at all.)
I don't think something like this exists yet, and collecting into a Vec<char> creates some overhead, but you can write such an iterator yourself with a little bit of trickery:
struct OwnedCharsIter {
s: String,
index: usize,
}
impl OwnedCharsIter {
pub fn new(s: String) -> Self {
Self { s, index: 0 }
}
}
impl Iterator for OwnedCharsIter {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
// Slice of leftover characters
let slice = &self.s[self.index..];
// Iterator over leftover characters
let mut chars = slice.chars();
// Query the next char
let next_char = chars.next()?;
// Compute the new index by looking at how many bytes are left
// after querying the next char
self.index = self.s.len() - chars.as_str().len();
// Return next char
Some(next_char)
}
}
fn greet(c: &str) -> String {
"Hello, ".to_owned() + c
}
fn main() {
let names = ["Martin", "Helena", "Ingrid", "Joseph"];
let iterator = names.into_iter().map(greet);
let chars_iter = iterator.flat_map(OwnedCharsIter::new);
println!("{:?}", chars_iter.collect::<String>())
}
"Hello, MartinHello, HelenaHello, IngridHello, Joseph"

Pass mut reference to a function, and get it back

I try to write a code sample since an hour, who add some spaces in a String. So the main borrow a String to a function who add spaces, and then ,I wanna get the string back in the main function.
fn main() {
...
let mut line = String::new();
line = make_spaces(5, &mut line);
}
fn make_spaces(number: u8, string: &mut String) -> &mut String {
for _ in 0..number {
string.push(' ');
}
string
}
But the borrow checker give me the following error :
error[E0308]: mismatched types
--> src/main.rs:14:12
|
14 | line = make_spaces(left_spaces, &mut line);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected struct `String`, found `&mut String`
| help: try using a conversion method: `make_spaces(left_spaces, &mut line).to_string()`
I'm new with rust, and I know I don't understand borrowing. But I searched the net, and I don't understand it any better.
As I understand, I give the line ownership to make_spaces function, and then I (try to) give the ownership of string back to the main function.
Could you tell me where I'm wrong what is the solution of this problem please ? I know it's a common issue, but I don't see anything simple about that on stackoverflow.
There are two ways to do what you're trying, but you're mixing the two:
Take a mutable parameter as a reference
fn main() {
let mut line = String::new();
make_spaces(5, &mut line);
}
fn make_spaces(number: u8, string: &mut String) {
for _ in 0..number {
string.push(' ');
}
}
In that case, the caller gives you a reference to a struct so that you can modify it in place. There is no need to return anything.
Move the parameter into the function, then return the modified value
fn main() {
let mut line = String::new();
line = make_spaces(5, line);
}
fn make_spaces(number: u8, mut string: String) -> String {
for _ in 0..number {
string.push(' ');
}
string
}
In that case, the string is moved into the make_spaces function, so you need to move it back to the caller by returning it.
You don't have to return anything: you received a reference to a struct the caller of the function already has.
Just do
fn main() {
let mut line = String::new();
make_spaces(5, &mut line);
// use line here
}
fn make_spaces(number: u8, string: &mut String) {
for _ in 0..number {
string.push(' ');
}
}

Parse String to most appropriate type automatically

How to parse some string to most appropriate type?
I know there is .parse::<>() method, but you need to specify type in advance like this:
fn main() {
let val = String::from("54");
assert_eq!(val.parse::<i32>().unwrap(), 54i32);
let val = String::from("3.14159");
assert_eq!(val.parse::<f32>().unwrap(), 3.14159f32);
let val = String::from("Hello!");
assert_eq!(val.parse::<String>().unwrap(), "Hello!".to_string());
}
But I need something like this:
fn main() {
let val = String::from("54");
assert_eq!(val.generic_parse().unwrap(), 54i32); // or 54i16 or 54 u32 or etc ...
let val = String::from("3.14159");
assert_eq!(val.generic_parse().unwrap(), 3.14159f32);
let val = String::from("Hello!");
assert_eq!(val.generic_parse().unwrap(), "Hello!".to_string());
}
Is there an appropriate crate for something like this? I don't want to re-invent the wheel for the umpteenth time.
EDIT
This is what I actually want to do:
struct MyStruct<T> {
generic_val: T,
}
fn main() {
let val = String::from("54");
let b = MyStruct {generic_val: val.parse().unwrap()};
let val = String::from("3.14159");
let b = MyStruct {generic_val: val.parse().unwrap()};
}
Error:
error[E0282]: type annotations needed for `MyStruct<T>`
--> src/main.rs:7:13
|
7 | let b = MyStruct {generic_val: val.parse().unwrap()};
| - ^^^^^^^^ cannot infer type for type parameter `T` declared on the struct `MyStruct`
| |
| consider giving `b` the explicit type `MyStruct<T>`, where the type parameter `T` is specified
You need to base things on the right Enum type and implement FromStr for it. Like this.
#[derive(PartialEq, Debug)]
enum Val {
Isize(isize),
F64(f64),
}
impl core::str::FromStr for Val {
type Err = & 'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match (s.parse::<isize>(), s.parse::<f64>()) {
(Ok(i),_) => Ok(Val::Isize(i)),
(Err(_), Ok(f)) => Ok(Val::F64(f)),
(Err(_), Err(_)) => Err("neither parser worked"),
}
}
}
fn main() {
assert_eq!("34".parse(), Ok(Val::Isize(34)));
assert_eq!("12.3".parse(), Ok(Val::F64(12.3)));
assert!("wrong".parse::<Val>().is_err());
}
Rust is a statically typed language. This means that the compiler needs to know the type of variables at compile time. There are three ways things can go from there:
If your strings are known at compile-time, then you might as well replace them with literal values in your code (eg. "54" → 54).
If you have some other way of knowing at compile time what type a given string should parse to, then you can specify the appropriate type when parsing the string: let a = "54".parse::<i32>().unwrap()
If your strings are only known at run-time and you want to autodetect the type, then you need to use some kind of enumerated value that will store the type alongside the value in your program:
use std::str::FromStr;
enum Value {
I32 (i32),
F32 (f32),
String (String),
}
impl Value {
fn new (s: &str) -> Value {
if let Ok (v) = s.parse::<i32>() {
Value::I32 (v)
} else if let Ok (v) = s.parse::<f32>() {
Value::F32 (v)
} else {
Value::String (s.into())
}
}
}
That way, the rest of your code will have a way of knowing what type was detected and to adjust its processing accordingly.

How to flat_map and split from an iterator of Strings

Is there a way to make this work without switching to using iter instead of into_iter?
let strings: Vec<String> = vec!["1 2".to_string(), "3 4".to_string()];
strings.into_iter().flat_map(|str| str.split(" "));
The problem is
error[E0515]: cannot return value referencing function parameter `str`
--> src/lib.rs:3:40
|
3 | strings.into_iter().flat_map(|str| str.split(" "));
| ---^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `str` is borrowed here
When using iter instead of into_iter, I get an iterator of references and everything works but I'd like to know if it's possible to make this work on an iterator of Strings.
The issue with your code is that you are doing those actions:
You are consuming your vector with into_iter
Thus, inside the closure, you are taking a String by value that you borrow with split
In your temporary iterator, you hold a reference to this string
Conclusion: you are trying to return a reference to a local variable.
To solve this issue, you must create owned strings from the split string, and collect them to not hold a reference anymore:
fn main() {
let strings = vec!["1 2".to_string(), "3 4".into()];
let result = strings.into_iter().flat_map(|str| str.split(" ").map(str::to_owned).collect::<Vec<_>>());
println!("{:?}", result.collect::<Vec<_>>());
}
In fact, this would be less costly to not consume the vector at first:
fn main() {
let strings = vec!["1 2".to_string(), "3 4".into()];
let result = strings.iter().flat_map(|str| str.split(" ")).map(str::to_owned);
println!("{:?}", result.collect::<Vec<_>>());
}
I had the same problem and end up creating an iterator that take the ownership of the string, here is the code. Since you're splitting by space it should fit
struct Words {
buf: String,
offset: usize,
}
impl Words {
fn new(buf: String) -> Words {
Words { buf, offset: 0 }
}
}
impl Iterator for Words {
type Item = String;
fn next(&mut self) -> Option<String> {
let s = &(self.buf)[self.offset..];
let left = s.chars().take_while(|x| x.is_whitespace()).count();
let right = left + s[left..].chars().take_while(|x| !x.is_whitespace()).count();
if left < right {
self.offset += right;
return Some(String::from(&s[left..right]));
}
None
}
}
Here how I use it
fn read_file<'a>(buf: impl BufRead) -> impl Iterator<Item = String> {
buf.lines().filter_map(Result::ok).flat_map(Words::new)
}

How do I send an interpolated string on a channel?

How do I store a variable in a string? I've read the examples, but they are all just println!().
//javascript
var url_str = "http://api.weather/city" + city_code + "/get";
//go
urlStr := fmt.Sprintf("http://api.weather/%s/get", cityCode)
// Edit: Rust
let url_str = format!("http://api.openweathermap.org/data/2.5/weather?q={}", city_code);
I am using tx.send() and want to send an interpolated string on the channel like this:
let url_str = "http://api.weather";
c.send(url_str);
but I get an error
src/http_get/http_getter.rs:21:17: 21:24 error: `url_str` does not live long enough
src/http_get/http_getter.rs:21 c.send(&url_str);
^~~~~~~
Here is the function that I am trying to implement for constructing the URL:
pub fn construct_url(c: &Sender<String>, city_code: &str) {
let url_str = format!("http://api.openweathermap.org/data/2.5/weather?q={}", city_code);
println!("{}", url_str);
c.send(url_str);
}
With elided lifetimes and types reinstated, here’s what you have:
pub fn construct_url<'a, 'b, 'c>(c: &'a Sender<&'b str>, city_code: &'c str) {
let url_str: String = format!("http://api.openweathermap.org/data/2.5/weather?q={}", city_code);
println!("{}", url_str);
c.send(&url_str);
}
Bear in mind the distinctions between String and &str: &str is a string slice, a reference to a string that someone else owns; String is the owned variety.
'b is necessarily at least as long as the entire function body—any string you construct inside the function will not live long enough for 'b. Therefore your sender will need to send a String, not a &str.
pub fn construct_url(c: &Sender<String>, city_code: &str) {
let url_str = format!("http://api.openweathermap.org/data/2.5/weather?q={}", city_code);
println!("{}", url_str);
c.send(url_str);
}

Resources