James Davies
James Davies

Reputation: 9859

Closure requires unique access to lambda function

I'm learning Rust, and have implemented some simple code to experiment with closures - but am running up against an issue with the borrow-checker that I'm not sure how to resolve.

When compiling the following function

fn twice(x:int, f:|int| -> int) -> int {
    f(f(x))
}

I get the following error

closure requires unique access to `f` but it is already borrowed

I'm working through the guide and have a moderate understanding of why the borrow-checker doesn't like this - but I'm unsure how to resolve it.

I can work around it by assigning the results of the first call to a temporary variable first, and then calling f(..) again on this. However this feels inelegant.

Is there a cleaner/better way of writing f(f(x)), or some way to convince the compiler that this is safe?

Upvotes: 1

Views: 551

Answers (2)

Shepmaster
Shepmaster

Reputation: 430663

In modern Rust, the original code compiles as-is:

fn twice(x: i32, f: impl Fn(i32) -> i32) -> i32 {
    f(f(x))
}

fn main() {
    twice(42, |i| dbg!(i));
}

Upvotes: 0

huon
huon

Reputation: 102066

The full error message is:

<anon>:2:7: 2:8 error: closure requires unique access to `f` but it is already borrowed
<anon>:2     f(f(x))
               ^
<anon>:2:5: 2:6 note: previous borrow of `f` occurs here; the unique capture prevents subsequent moves or borrows of `f` until the borrow ends
<anon>:2     f(f(x))
             ^
<anon>:2:12: 2:12 note: previous borrow ends here
<anon>:2     f(f(x))
                   ^

That is, the outer call is, in some sense, reserving f and preventing it from being used first. This is very similar to issue #6268, which concerns methods instead of closures.

As you say, using a temporary is a fix, and is the most reasonable fix.

fn twice(x:int, f:|int| -> int) -> int {
    let y = f(x);
    f(y)
}

Upvotes: 3

Related Questions