Why does this closure argument need an explicit type?

Viewed 2579

Consider the following working code:

fn f() {
    let xs = vec![(0, 0)];
    let f = |j| xs[j];
    let y = f(0usize);
}

The following variation does not compile:

fn f() {
    let xs = vec![(0, 0)];
    let f = |j| xs[j].0;
    let y = f(0usize);
}

It fails as follows:

error[E0282]: type annotations needed
 --> src/lib.rs:3:17
  |
3 |     let f = |j| xs[j].0;
  |                 ^^^^^ cannot infer type
  |
  = note: type must be known at this point

To fix it, one must annotate j:

fn f() {
    let xs = vec![(0, 0)];
    let f = |j: usize| xs[j].0;
    let y = f(0usize);
}

The Rust book says:

Closures don’t require you to annotate the types of the parameters or the return value like fn functions do.

Why must j be explicitly typed?

1 Answers

As explained in the duplicate suggested by @Stargateur, Rust needs to know the type of the index so that it can determine the type of the result. In your first example, this is not an issue because you don't use xs[j] nor the result of the closure, so the compiler feels free to leave them as "some as yet undefined type" and optimizes them away without ever needing to know the type.

In your second example however, you try to access xs[j].0, for which the compiler needs to know the type of xs[j] in order to know what to do with the .0.

Related