Suppose I'm writing a function which trims whitespace around a &str
and then parses it to a generic type (this is a simplified example: my real function is grabbing several capture groups from a regex).
fn trim_and_parse<T: FromStr>(s: &str) -> T {
s.trim().parse().unwrap()
}
so I could do for example
let n: u32 = trim_and_parse(" 24 ");
let inner: String = trim_and_parse(" hi ");
This works great, but that second one is allocating a new String
. I'd really like it if I could return a slice of the input instead:
let inner: &str = trim_and_parse(" hi ");
This doesn't work because &str
isn't FromStr
, and I'm not sure it would really make sense for it to be. Is there anything I can do to make this interface work, so that if I use eg u32
as the type parameter then it parses the trimmed string into a number, but I can use something else as the type parameter to get a slice of the original string instead?
I tried experimenting with something like
trait MyFromStr {
fn from_str(s: &str) -> Self;
}
impl MyFromStr for &str {
fn from_str(s: &str) -> Self {
s
}
}
which gets a lifetime may not live long enough
which is fair enough. Is there another way to make this work?
You can do that by declaring the trait to have a lifetime:
trait MyFromStr<'a>: Sized {
type Err;
fn from_str(s: &'a str) -> Result<Self, Self::Err>;
}
impl<'a> MyFromStr<'a> for &'a str {
type Err = std::convert::Infallible;
fn from_str(s: &'a str) -> Result<Self, Self::Err> {
Ok(s)
}
}
impl<'a> MyFromStr<'a> for i32 {
type Err = std::num::ParseIntError;
fn from_str(s: &'a str) -> Result<Self, Self::Err> {
s.parse()
}
}
fn trim_and_parse<'a, T: MyFromStr<'a>>(s: &'a str) -> T
where
T::Err: std::fmt::Debug,
{
MyFromStr::from_str(s.trim()).unwrap()
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.