Debugging issues with traits, trait bounds, and closures

⚓ Rust    📅 2025-11-08    👤 surdeus    đŸ‘ī¸ 3      

surdeus

The issue[1]:

I can't clean-up / figure out - two of my code samples. Let's call them V7 and V8.

V7 Playground: Link
Lots of errors. Too many places where the issue may be.

V8 Playground: Link
This, I assume, was the "solution" to V7, but on closer inspection, it is not.


Stopping point 1:

V7.1 Playground: Link - Reduced errors to one: type annotations needed. if I comment out all the FnMut code, the error re-appears on the FnOnce code. - So something is overlapping.

help: try using a fully qualified path to specify the expected types
52 -     let v2 = w2.get_value()(1);
52 +     let v2 = <Wrap<'_, _> as GetValue<T>>::get_value(&w2)(1);

Sanity Check:
SC1 Playground: Link - Implement 3 closures with Fn, FnMut, FnOnce trait bounds. Looks OK to me.


Stopping point 2:
On a fluke, I tried combining all the trait implementations into one with multiple bounds -- since all three execute the same statement. [progress unlocked].

Sanity Check:
SC2 Playground: Link - A struct with Fn FnMut FnOnce closure traits -- No lifetimes needed. No dyn keyword needed. No type annotations on the trait definition needed. Big wins here.

Applying my learnings:
V7.2 Playground: Link - The FnMut and FnOnce closures are not taking, even though they has been checked dozens of times. -- But get this -- comment out the Fn() trait bound -- and everything works.

25 |     let f2 = |x: i32| {
   |              ^^^^^^^^ this closure implements `FnMut`, not `Fn`
26 |         n_copy += x;
   |         ------ closure is `FnMut` because it mutates the variable `n_copy` here
...
39 |     let v2 = w2.value.get_value(2);
   |              -------- --------- required by a bound introduced by this call
   |              |
   |              the requirement to implement `Fn` derives from here

V8.1 Playground: Link - I realized that in V8, the FnMut closure was not correct. Updating it. I ran into an issue with the borrow. But touching the borrows in V8.1 just blows everything up.

error[E0596]: cannot borrow data in a `&` reference as mutable
35 |     let v2 = w2.get_value()(1);
   |              ^^^^^^^^^^^^^^ cannot borrow as mutable

I need a better way to go about debugging V7.2 and V8.1. The whole Every function you define creates a unique, zero-sized type called a function item thing, adds a layer of difficulty in getting the trait bounds right.

So, given a closure X, how do you go about finding the trait bound (or implementation) that best matches X?
.
.
.
.
In hindsight, some compiler suggestions (triggered by user error) that I shouldn't have taken:

  • try borrowing.(&)
  • try adding a lifetime('a)
  • try wrapping in a Box::new()
  • try using dyn Fn()

  1. My apologies in advance, I know this versions of this question has been asked over and over again on the forum. â†Šī¸Ž

1 post - 1 participant

Read full topic

đŸˇī¸ Rust_feed