Closures, explanation needed

fn main() {
    let x = vec![1, 2, 3];

    let equal_to_x =  |z| z == x;

    println!("X is: {:?}", x);

    let y = vec![1, 2, 3];

    assert!(equal_to_x(y));
}
Doesn't compile:
fn main() {
    let x = vec![1, 2, 3];

    let equal_to_x =  ||  x;//Why this line moves x and same line in the example above doesn't???

    println!("X is: {:?}", x);
}


The == operator only takes its arguments by reference, since z == x stands for PartialEq::eq(&z, &x). If a closure only uses a variable “by reference”, i.e. uses &x, then it only needs to “capture” the variable by reference. This means, the closure equal_to_x in the first example contains a reference &x and after creating the closure, x is borrowed immutably, such that a second immutable borrow (from the println! macro) is possible.

By contrast, the (inadequately named) equal_to_x in the second example uses x directly, by value, as it will, when called, return the value that once was in x. In order to be able to return the contents of x, when created, it captures the value in x and thus moves out of x. Since x is moved out of, the println! cannot borrow x immutably anymore.

1 Like

For illustration purposes: Here are some translations of your closures:

fn main() {
    let x = vec![1, 2, 3];

    struct Closure<'a> {
        x_ref: &'a Vec<i32>,
    }
    impl<'a> Fn<(Vec<i32>,)> for Closure<'a> {
        fn call(&self, (z,): (Vec<i32>,)) -> bool {
            PartialEq::eq(&z, self.x_ref)
        }
    }
    // impl's for FnMut and FnOnce omitted

    let equal_to_x = Closure { x_ref: &x };

    println!("X is: {:?}", x);

    let y = vec![1, 2, 3];

    assert!(equal_to_x(y));
}

(playground)


fn main() {
    let x = vec![1, 2, 3];
    
    struct Closure {
        x: Vec<i32>,
    }
    impl FnOnce<()> for Closure {
        // type Output omitted
        fn call_once(self, (): ()) -> Vec<i32> {
            self.x
        }
    }

    let equal_to_x = Closure { x };

    println!("X is: {:?}", x);
}

(playground)


click the links to the respective playground to get all the details

2 Likes