Extending Lifetimes - A better route?

Hi All,

So I have a construct where I need to take some optional values and push them to a vector if used (I'm building a SQL query).

Ideally I would write it as:

fn main() {
    
    
    let optional = Some(4);
    
    let mut params = vec![];
    
    if let Some(number) = optional {
        params.push(&number);
    }
    
    uses_borrow(&params)
    
}


fn uses_borrow(params: &[&i64]) {
    //would do something.
    println!("{:?}", params);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0597]: `number` does not live long enough
  --> src/main.rs:9:21
   |
9  |         params.push(&number);
   |                     ^^^^^^^ borrowed value does not live long enough
10 |     }
   |     - `number` dropped here while still borrowed
11 |     
12 |     uses_borrow(&params)
   |                 ------- borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

Obviously this fails because of the lifetime of number. However I (as a human) can reason that the lifetime of number could just be extended. However I don't see a way to do this.

Instead my workaround has been to create a variable with a longer scope which is essentially just the value inside the option or 0 otherwise. However this doesn't feel quite right. Also it means I have to create a load of additional variables for each option. Am I missing a better way?

Possible solution:

fn main() {
    
    
    let optional = Some(4);
    let mut optional_value = 0;
    
    let mut params = vec![];
    
    if let Some(number) = optional {
        optional_value = number;
        params.push(&optional_value);
    }
    
    uses_borrow(&params)
    
}


fn uses_borrow(params: &[&i64]) {
    //would do something.
    println!("{:?}", params);
}

(Playground)

Output:

[4]

Errors:

   Compiling playground v0.0.1 (/playground)
warning: value assigned to `optional_value` is never read
 --> src/main.rs:5:9
  |
5 |     let mut optional_value = 0;
  |         ^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_assignments)]` on by default
  = help: maybe it is overwritten before being read?

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 0.97s
     Running `target/debug/playground`

Try this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5efbaf51d83ab404f3fc900b3f286887

2 Likes

There’s very little reason to ever store an &i64: A plain i64 takes the same space on most platforms, and it’s Copy so there’s no cloning overhead:

fn main() {
    let optional = Some(4);
    let mut params = vec![];
    
    if let Some(number) = optional {
        params.push(number);
    }
    
    uses_borrow(&params)
}


fn uses_borrow(params: &[i64]) {
    //would do something.
    println!("{:?}", params);
}

or you could just do

    if let Some(number) = &optional {
        params.push(number);
    }

or even

    if let Some(ref number) = optional {
        params.push(number);
    }
2 Likes

Perfect - thank you all. That makes much more sense. I can just get a reference to the value inside the enum.