error[E0716]: temporary value dropped while borrowed. When using builder pattern

I'm getting this error, I'm not sure how to solve this.

Scanner implementation:

use crate::token::Token;

pub struct Scanner {
    source: String,
    tokens: Vec<Token>,
}

impl Scanner {
    pub fn new(source: String) -> Scanner {
        Scanner {
            source,
            tokens: vec![],
        }
    }

    pub fn scan_tokens(&mut self) -> &mut Scanner {
       // Scan tokens here
 
       self
    }

    pub fn get_tokens(&self) -> &Vec<Token> {
        &self.tokens
    }
}

I'm using the above defined struct as follows:

pub fn run(input: String) -> Result<()> {
    let mut scanner = Scanner::new(input).scan_tokens();

    let tokens = scanner.get_tokens();
    Ok(())
}

But the compiler gives the following error:

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:12:23
   |
12 |     let mut scanner = Scanner::new(input).scan_tokens();
   |                       ^^^^^^^^^^^^^^^^^^^              - temporary value is freed at the end of this statement
   |                       |
   |                       creates a temporary which is freed while still in use
13 |
14 |     let tokens = scanner.get_tokens();
   |                  -------------------- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

The error goes away when I do something like this.

pub fn run(input: String) -> Result<()> {
    let mut scanner = Scanner::new(input);
    scanner.scan_tokens();

    let tokens = scanner.get_tokens();
    Ok(())
}

But I want to do as written here: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html#non-consuming-builders-(preferred):

Generally with builders you are supposed to either chain all the commands together (so like Scanner::new(input).scan_tokens().get_tokens()) or assign the builder to one variable first and then do all the operations (like what you do in the snippet that works).

However in your particular case the first way won't work anyway because your get_tokens function returns a value that borrows from self and builders are not supposed to do that (the final value should not require the builder to stay alive!)

Overall I don't think your code fits a Builder pattern. I don't think you even need a struct for this, what you're doing only requires a function that takes a string as input (probably a &str, no need for an allocation) and returns a Vec<Token>. A struct might be needed if you wanted a streaming Scanner, in that case you would hold only the source and the current point you reached, but not the tokens (those would still be yielded when needed).

ps: the page you linked is for rust 1.0.0 and a couple of things have changed since then. I don't think f: proc():Send is valid anymore...

If you want the chain to work with temporary builders (all on one line), the key point is to return something owned from any finalization step, e.g.:

    pub fn take_tokens(&mut self) -> Vec<Token> {
        std::mem::take(&mut self.tokens)
    }

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.