How to tell if a closure` borrow` or `take ownership of` a binding?


#1
fn main() {
    let num = 5;
    //borrow the binding.
    let plus_num = |x: i32| x + num;   
    let nums = vec![1, 2, 3];
    //take ownership
    let takes_nums = || nums;
    println!("{:?}", nums);   
}

Why plus_num closure borrows the num binding, but takes_num takes the ownership of nums binding?
What makes this difference?


#2

Who says it isn’t? The comparison is invalid because i32 is a Copy type, but Vec<_> isn’t. Thus, even if it moved num, it wouldn’t matter, because it wouldn’t invalidate the original binding.

Here’s a better example:

fn main() {
    {
        //borrow the binding.
        let nums = vec![1, 2, 3];
        let nums_len = || nums.len();
        println!("{:?}", nums);
    }
    {
        //take ownership
        let nums = vec![1, 2, 3];
        let takes_nums = || nums;
        println!("{:?}", nums); // error: use of moved value: `nums`
    }
}

The nums_len closure works because Vec::len only requires an immutable borrow of the subject, so there’s no reason to take ownership of nums.

takes_nums doesn’t work for exactly the same reason: there is no way to make the closure work without taking ownership of nums, so it does so.

So to answer your question: a closure takes ownership of a value if it has to (or if you require it do so using move).


#3

Thanks.Your explain is very clear.

let num = 5;
let plus_num = |x: i32| x + num;
assert_eq!(10, plus_num(5));

This closure, plus_num, refers to a let binding in its scope: num. More specifically, it borrows the binding. If we do something that would conflict with that binding, we get an error. Like this one:
https://doc.rust-lang.org/stable/book/closures.html#closures-and-their-environment

So the copy is a kind of borrow?


#4

I don’t know if it is or is not a borrow in that case. Addition for i32 is overloaded in enough ways that the closure is valid whether num is borrowed or copied.

A type being Copy just means that moving a value of that type does not invalidate the binding that was moved from.