Rust lifetime mismatch - 'a does not necessarily outlive lifetime as defined here
19:14 03 Nov 2023

I'm running into lifetime issues when trying to move borrowed data between structs. At a high level I'd like to do something like:

  • read a yml file into a string buffer
  • deserialize that into a struct using from_str
  • create a different struct from that same borrowed data
  • write that out to a file

Here's a sample implementation of what I built that gives the lifetime error:

Rust playground link

use serde::{Serialize, Deserialize};

#[derive(Deserialize, Debug, Serialize)]
pub struct Foo<'a> {
  name: &'a str
}

impl<'a> Foo<'a> {
    
    pub fn new(name: &'a str) -> Self {
        Self { name }
    }
}

#[derive(Deserialize, Debug, Serialize)]
pub struct Bar<'a> {
  name: &'a str
}

impl<'a> Bar<'a> {
    
    pub fn new(name: &'a str) -> Self {
        Self { name }
    }
}


pub trait Visitor {
    type Value;
    fn visit_table_borrowed<'a>(&mut self, t: &'a Foo<'a>) {
        let _ = t;
    }
}

pub trait DataBorrowed {
    fn accept(&self, visitor: &mut V);
}

impl<'a> DataBorrowed for Foo<'a> {
    fn accept(&self, visitor: &mut V) {
        visitor.visit_table_borrowed(self)
    }
}


impl<'a> Visitor for Bar<'a> {
    type Value = Bar<'a>;
    fn visit_table_borrowed(&mut self, t: &'a Foo<'a>) {
       self.name = t.name;
    }
}

impl<'a> From> for Bar<'a> {
    fn from(dt: Foo<'a>) -> Self {
        let mut table = Bar::new("bar");
        dt.accept(&mut table);
        table
    }
}

fn main() {
    let f = Foo::new("foo");
    let b: Bar = Bar::from(f);
    
}


The error:

error[E0308]: method not compatible with trait
  --> src/main.rs:49:5
   |
49 |     fn visit_table_borrowed(&mut self, t: &'a Foo<'a>) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected signature `fn(&mut Bar<'a>, &'a Foo<'a>)`
              found signature `fn(&mut Bar<'a>, &'a Foo<'a>)`
note: the lifetime `'a` as defined here...
  --> src/main.rs:49:5
   |
49 |     fn visit_table_borrowed(&mut self, t: &'a Foo<'a>) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined here
  --> src/main.rs:47:6
   |
47 | impl<'a> Visitor for Bar<'a> {
   |      ^^

For more information about this error, try `rustc --explain E0308`.
rust borrow-checker