 # Borrow in a closure

Hi, I never gave this a thought but now I’m struggling to explain to myself how the borrowing happens in rust closures. Consider this playground link:

``````fn main() {
#[derive(Eq, PartialEq, Clone)]
struct A { a: Vec<u8> }

let a = A { a: vec![1, 2, 3] };
let c = A { a: vec![1, 2, 3] };

let mut b = vec![a.clone(), a.clone(), a];

// if let Some(pos) = b.iter().position(|elt| elt == c) { // This will error out
if let Some(pos) = b.iter().position(|elt| *elt == c) {
let _ = b.remove(pos);
b.push(c);
}
}
``````

I get that the closure is borrowing `c`. The borrow can be either `&` or `&mut`. In this case it’s `&` (i think). So why do i have to do `*elt ==` ? Why doesn’t `elt == c` work ? as `elt` and borrowed `c` inside closure should both have the type `&A` ? If `A` was copy-able i could understand that maybe a copy of it was created and then the value semantics makes sense. However it’s not (it’s move-able). So if `c` inside the closure has type `A` then that would imply it was moved. How can i then use it in `b.push(c)` ? Of-course i think it wasn’t moved (and the closure doesn’t even have `move` prefix) and hence my confusion.

Semantically, the `c` inside the closure has exactly the same type as the `c` outside. The actual capture behind the scenes will depend on how the variable is used.

I think the additional trick you’re missing is that `==` calls `PartialEq::eq` with references to its two operands. You have `elt: &A` since you’re iterating by reference, and `c: A` because that’s how that variable was defined, regardless of the closure.

So `*elt == c` matches the types, calling `<A as PartialEq>::eq(&*elt, &c)`. Since the closure is only using `c` by reference, it doesn’t need to capture/move the actual value.

(and the closure doesn’t even have `move` prefix)

It’s not necessary to use the `move` prefix if a closure does something that actually requires a move. But sometimes you want to use `move` anyway so the closure is not restricted to the borrowed scope of its captures. For instance, if you wanted to return an iterator like `iter.filter(|elt| *elt == c)`, then you would need the closure to own `c` to be returned with it, rather than just borrowing a reference.

4 Likes

It seems that you don’t know how closures are desugarred, the desugarring is really simple and knowing it will help you understand why what @cuviper said is true. You can read about it in my blog on the topic here:

2 Likes

``````let mut counter: u32 = 0;
let delta: u32 = 2;
...
let mut next = __closure_4__ {
counter: &mut counter,
delta: &delta
};
``````

So for me in my example, the `c` outside the closure has the type `A`. The `c` inside the closure has the type `&A` (which i also said in my OP) and it references the `c` outside the closure. This is also what you blog says - so pretty sure we are in the same page there.

The thing that I was perhaps missing was what @cuviper said about `PartialEq` taking the LHS RHS by reference. Now it all makes sense. `*p == c` becomes `PartialEq::eq(&self, &A)`. Since `c` inside the closure is of type `&A` already, there’s no problem and things work. You need to deref `p` just like normally one would do `obj.mem_fun()` (where `obj: Object`) which would translate to `mem_fun(&self) <==> mem_fun(&Object)`.

With that in place things make sense to me now.

Here is your code slightly rewritten to explicit the stuff mentioned in this thread:

``````#[derive(Eq, PartialEq, Clone)]
struct A {
a: Vec<u8>,
}

fn main ()
{
let mut b = {
let a = A {
a: vec![1, 2, 3],
};
vec![a.clone(), a.clone(), a]
};
let c = A { a: vec![1, 2, 3] };

let closure = |elt: &A| -> bool {
// here, the value actually captured is &c :
//  A::eq(elt, &c)
//  *elt == *(&c)
*elt == c
};
fn assert_Fn (_: &impl Fn(&A) -> bool) {}
assert_Fn(&closure);

if let Some(pos) = b.iter().position(closure) {
let _ = b.remove(pos);
b.push(c);
}
}
``````

The important thing to understand is that `c` within the closure is sugar for `*(&c)`, where `&c` is the actual value captured by the closure (thanks to `_ == _` only taking references to its operands):

``````
struct Closure<'c> {
at_c: &'c A,
}

impl<'elt> Fn<(&'elt A,)> for Closure<'_> {
extern "rust-call"
fn call (
self: &'_ Self,
(elt,): (&'elt A,),
) -> bool
{
*elt == *self.at_c
}
}

fn main ()
{
let mut b = {
let a = A {
a: vec![1, 2, 3],
};
vec![a.clone(), a.clone(), a]
};
let c = A { a: vec![1, 2, 3] };

let closure = Closure { at_c: &c };
fn assert_Fn (_: &impl Fn(&A) -> bool) {}
assert_Fn(&closure);

if let Some(pos) = b.iter().position(closure) {
let _ = b.remove(pos);
b.push(c);
}
}
``````
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.