11

I have the following code:

pub struct Canvas<'a> { width: isize, height: isize, color: Color, surface: Surface, texture: Texture, renderer: &'a Renderer, } impl<'a> Canvas<'a> { pub fn new(width: isize, height: isize, renderer: &'a Renderer) -> Canvas<'a> { let color = Color::RGB(0, 30, 0); let mut surface = core::create_surface(width, height); let texture = Canvas::gen_texture(&mut surface, width, height, color, renderer); Canvas { width: width, height: height, color: color, surface: surface, texture: texture, renderer: renderer, } } pub fn color(&mut self, color: Color) -> &mut Canvas<'a> { self.color = color; self.texture = Canvas::gen_texture( &mut self.surface, self.width, self.height, self.color, self.renderer, ); self } } 

I would like to be able to do this:

let mut canvas = Canvas::new(100, 100, &renderer).color(Color::RGB(80, 230, 80)); 

I get this error:

error: borrowed value does not live long enough let mut canvas = Canvas::new(100, 100, &renderer)

Why does the returned Canvas object not live long enough? If I store the result in an intermediate let, then it works; why?

1
  • 1
    This code cannot be compiled on the playpen, specifically because you reference many structures that aren't defined. Please review how to create an MCVE, and pay attention to the minimal part. Commented Feb 12, 2015 at 5:07

1 Answer 1

19

Here's a minimal reproduction:

#[derive(Debug)] pub struct Canvas; impl Canvas { fn new() -> Self { Canvas } fn color(&self) -> &Canvas { self } } fn main() { let mut canvas = Canvas::new().color(); // 1 ^~~~~~~~~~~~~ // 2 ^~~~~ println!("{:?}", canvas); } 

Rust 2015

error[E0597]: borrowed value does not live long enough --> src/main.rs:15:22 | 15 | let mut canvas = Canvas::new().color(); | ^^^^^^^^^^^^^ - temporary value dropped here while still borrowed | | | temporary value does not live long enough ... 19 | } | - temporary value needs to live until here | = note: consider using a `let` binding to increase its lifetime 

Rust 2018

error[E0716]: temporary value dropped while borrowed --> src/main.rs:15:22 | 15 | let mut canvas = Canvas::new().color(); | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | | creates a temporary which is freed while still in use ... 18 | println!("{:?}", canvas); | ------ borrow later used here | = note: consider using a `let` binding to create a longer lived value 

The problem arises because you create a temporary variable (1), then pass the reference to that variable to the method (2), which returns the reference. At the end of the method chain, you are trying to return the reference and store it in the variable, but the reference points to a temporary item that has nowhere to live! Rust doesn't let you have a reference to something that's invalid.

Part of the problem is that this is not the Builder pattern, this is just a struct that modifies itself using chained method invocation. Some solutions:

  1. Store the "temporary" variable, in which case all the methods are just normal mutation methods that happen afterward.
  2. Take in self instead of a reference to self (&self, &mut self) and then ultimately return the full struct.
  3. Have a build method at the end of the chain that returns another standalone struct, not a reference.
Sign up to request clarification or add additional context in comments.

2 Comments

What you write all makes sense, but why doesn't Rust hit me with an error at the time I'm declaring the canvas variable? Why allow the declaration of something that later can't be used under any circumstances? If you remove println!("{:?}", canvas); the program compiles fine which is a bit misleading because it led me to believe that binding to the canvas variable is fine. But it isn't and it can never be.
why temp variable dies instead of being stored in the current scope? is there any set of rules that explains it?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.