Borrow Checker Issue


Hi Rust Community. I am learning Rust and came across an issue that is strange to me and I couldn't figure it out after research. In my code burrow checker complains that the lifetime of circle and rect is shorter than lifetime of their references. However, they and their references are in the same scope or Am I missing something here? does stdout burrows the references over the lifetime of main ?

Welcome to the Rust forum! When posting code, please be mindful that it's way better for others if you post it in text form, so that people trying to help you can run the code and do the necessary modifications if necessary.

That being said, you should familiarize yourself with 'static lifetimes. They are special in Rust and you should only use them for very special use cases (read: Don't use them).

Since you have just started learning Rust, I would advise you against using references at all until you feel comfortable with the borrow checker.

In the meantime, using a non-static lifetime for the trait objects fixes your error:

pub struct Shape<'a> {
  shapes: Vec<&'a dyn Draw>
}
1 Like

Many Thanks for your advice but I also tried your suggestion however the issue is still the same. Burrow checker complains that borrowed value does not live long enough coercion requires that rect and circle is borrowed for 'static. Any Idea why?

trait Draw{
  fn draw(&self)-> String;
}

impl  core::fmt::Debug for dyn Draw{
  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
    write!(f, "{}", self.draw())
  }
}

struct Point {
  x: f32,
  y: f32,
}

struct Circle {
  center: Point,
  radius: f32,
}

impl  Circle{
  fn new(x:f32, y:f32, radius: f32) -> Self {
    Self { center:Point{x, y}, radius }
  }
}

impl Draw for Circle {
  fn draw(&self) -> String {
    format!("Circle at x: {}, y: {} with {} radius.", self.center.x, self.center.y, self.radius)
  }
}

struct Rectangle {
  top_left: Point,
  width: f32,
  height: f32,
}

impl Rectangle {
  fn new(x:f32, y:f32, width: f32, height: f32) -> Self {
    Self{ top_left:Point{x,y},width,height }
  }
}

impl Draw for Rectangle {
  fn draw(&self) -> String {
    format!("Rect at x: {}, y:{}, width: {}, height: {}", self.top_left.x, self.top_left.y, self.width, self.height)
  }
}

pub struct Shape <'a> {
  shapes: Vec<&'a dyn Draw>
}

fn main() 
{
  let circle = Circle::new(0.0, 0.0, 5.0);
  let rect = Rectangle::new(0.0, 0.0, 5.0, 5.0);
  let shape = Shape{shapes:vec![&circle, &rect]};
  println!("{:?}", shape.shapes);
}

Hi @ug595 ,

The 'static lifetime gets implied by the Debug implementation.

First solution (playground):

impl std::fmt::Debug for dyn Draw + '_ {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
       write!(f, "{}", self.draw())
   }
}

Second solution (playground):

impl std::fmt::Debug for &dyn Draw {
   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
       write!(f, "{}", self.draw())
   }
}
1 Like

Thanks @maarten
This was the reason I confused. Apparently I am just starting to learn rust and not fully aware of the lifetime implication in Debug. This helped me to understand the issue.

It's not about Debug, but whenever dyn appears, there is a lifetime too, and you have to specify that lifetime if the default is not right.

https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes

1 Like