Another 'x' does not live long enough


#1

I would say, that I am fairly advanced with rust and do understand the borrow checker in most situation. In this case however, I can’t get my head around.

I try to solve a CodeSignal task. My solution looks like this (warning spoiler to everyone who wants to solve digitsProduct on her/his own!!!)

https://play.rust-lang.org/?gist=59c9ab39c9b4cd2405a74038f88bca25&version=nightly&mode=debug&edition=2015

fn digitsProduct(product: i32) -> i32 {
    (2..=product/2)
        .flat_map(|x| 
            (2..=product/2)
                .filter(|y| x * y == product)
                .map(|y| (x, y)))
        .map(|(a, b)| a*10+b)
        .min().unwrap()
}

fn main() {
    assert_eq!(26, digitsProduct(12));
}

It complains that x does not live long enough, but x is a i32! It is copyable!

I never encountered a borrow error for trivial-copyable types. What am I missing?


#2
fn digitsProduct(product: i32) -> i32 {
    (2..=product/2)
        .flat_map(|x|
            (2..=product/2)
                .filter(move |y| x * y == product)
                .map(move |y| (x, y)))
        .map(|(a, b)| a*10+b)
        .min().unwrap()
}

fn main() {
    assert_eq!(26, digitsProduct(12));
}

The compiler has to guess how it’s supposed to capture the environment. I don’t know exactly how it does this, but my mental model is: if the types check with borrowing, it borrows. This means that it sometimes guesses “borrow”, when borrow checking later fails.

The solution is to ensure it captures the offending variable by value rather than by reference.


#3

Thank you very much :heart:

Maybe I should file a bug at github to suggest move for the closure (A-Diagnostic)?


#4

Any borrow lives until the end of it’s definition scope. In your case that is function’s body.