Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can I return a slice of a &str input if the return type is generic?

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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 e.g. 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?

>Solution :

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()
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading