Is `let _ = {capture}` something special in the closures?

I was playing with lifetimes and trying to restrict moving data to closures. I was checking if data was moved to the closure with let _ = {capture}. It seamed that closures were always capturing my data no matter what until I tried to acrtually access my captures…

Code:

fn test_scope(data: &Vec<u8>) {
    run_scope(|| {
        let _ = data;           // compiles
        // let _wtf = data;     // doesn't compile
        // let _ = &data;       // doesn't compile
        // let _ = data.len();  // doesn't compile
    });
}

fn run_scope(f: impl Fn() + 'static) { // yes, it must be 'static here
    f()
}

I understand why bottom 3 cases don’t compile and I expect that.

What is a mistery to me is why does #1 compile… Closure is `static and without move, it should not be allowed to capture anything that is not static. But my &Vec<u8> is not static yet let _ seams to have access/capture to it.

Can please someone describe what is happening here?

Isn’t simply because the wildcard pattern does not move variables?

2 Likes

Bu shouldn’t it fail the moment I type data anywhere in the closure? It should not be captured after all.

_ is a very special do-nothing pattern. It’s quite different from _var that is merely unused.

1 Like

And to answer the usual next question: while at the top level this is sometimes surprising, it’s really important that it works this way for nested patterns.

if let Some(_) = foo {
    pass_ownership(foo);
}

really needs to not move foo as part of that pattern, so let _ = foo also doesn’t move foo.

7 Likes