13

I want to implement FromStr for a struct with a lifetime parameter:

use std::str::FromStr;

struct Foo<'a> {
    bar: &'a str,
}

impl<'a> FromStr for Foo<'a> {
    type Err = ();
    fn from_str(s: &str) -> Result<Foo<'a>, ()> {

        Ok(Foo { bar: s })
    }
}

pub fn main() {
    let foo: Foo = "foobar".parse().unwrap();
}

However, the compiler complains:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:11:12
   |
11 |         Ok(Foo { bar: s })
   |            ^^^
   |
help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Foo<'a>, ()>
  --> src/main.rs:9:5
   |
9  |     fn from_str(s: &str) -> Result<Foo<'a>, ()> {
   |     ^

Changing the impl to

impl<'a> FromStr for Foo<'a> {
    type Err = ();
    fn from_str(s: &'a str) -> Result<Foo<'a>, ()> {
        Ok(Foo { bar: s })
    }
}

gives this error

error[E0308]: method not compatible with trait
  --> src/main.rs:9:5
   |
9  |     fn from_str(s: &'a str) -> Result<Foo<'a>, ()> {
   |     ^ lifetime mismatch
   |
   = note: expected type `fn(&str) -> std::result::Result<Foo<'a>, ()>`
   = note:    found type `fn(&'a str) -> std::result::Result<Foo<'a>, ()>`
note: the anonymous lifetime #1 defined on the block at 9:51...
  --> src/main.rs:9:52
   |
9  |     fn from_str(s: &'a str) -> Result<Foo<'a>, ()> {
   |                                                    ^
note: ...does not necessarily outlive the lifetime 'a as defined on the block at 9:51
  --> src/main.rs:9:52
   |
9  |     fn from_str(s: &'a str) -> Result<Foo<'a>, ()> {
   |                                                    ^
help: consider using an explicit lifetime parameter as shown: fn from_str(s: &'a str) -> Result<Foo<'a>, ()>
  --> src/main.rs:9:5
   |
9  |     fn from_str(s: &'a str) -> Result<Foo<'a>, ()> {
   |     ^

Playpen

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Piotr Zolnierek
  • 1,030
  • 1
  • 10
  • 19

1 Answers1

15

I don't believe that you can implement FromStr in this case.

fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err>;

There's nothing in the trait definition that ties the lifetime of the input to the lifetime of the output.

Not a direct answer, but I'd just suggest making a constructor that accepts the reference:

struct Foo<'a> {
    bar: &'a str
}

impl<'a> Foo<'a> {
    fn new(s: &str) -> Foo {
        Foo { bar: s }
    }
}

pub fn main() {
    let foo = Foo::new("foobar"); 
}

This has the side benefit of there not being any failure modes - no need to unwrap.

You could also just implement From:

struct Foo<'a> {
    bar: &'a str,
}

impl<'a> From<&'a str> for Foo<'a> {
    fn from(s: &'a str) -> Foo<'a> {
        Foo { bar: s }
    }
}

pub fn main() {
    let foo: Foo = "foobar".into();
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • **Why** doesn't `FromStr` support this? Is there a good reason to disallow values returned from `FromStr::from_str` from referencing the input? – RBF06 Mar 15 '23 at 22:23
  • @RBF06 "because that's the way it was written" is the most accurate answer. That is just what most usages of `FromStr` were and now it's stable. – Shepmaster Apr 14 '23 at 20:51