1
votes

I'm currently reading the Rust book, and I have just reached the topic closures. A detail that has surprised me, is that the Rust book sais that

Closures don’t require you to annotate the types of the parameters

I immeadiatly tested that, since it appeared really counter-intuitive to how Rust usually works. Thus, i copied exactly the closure they used, pasted it into my code, and... got an error:

fn some_closure() {
    let expensive_closure = |num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    };
}
error[E0282]: type annotations needed
  --> src/main.rs:14:30
   |
14 |     let expensive_closure = |num| {
   |                              ^^^ consider giving this closure parameter a type

error: aborting due to previous error

I sure know the meaning of that error, still I am confused by it, since not only the book, but also the reference specify that theres no annotations needed, yet I am getting this error.

Is this just a recent change that hasn't been documented yet, or is there something I misunderstand?

2
num is used in absolutely no way. So there's absolutely no way to determine its type. Did you want to use num instead of 2 in the closure ? Is that a typo ?Denys Séguret
In addition to what the answer says, there are also cases where the compiler could figure out the types, but doesn't (yet). You shouldn't take "don't require you to annotate" as 100% guarantee, it's more of a best-effort attempt to intuit the types. (But this differs from functions where no such attempt exist, intentionally.) Also, you can count on future versions of the compiler to only require annotations in fewer cases, as failing to compile existing code would be a breaking change.user4815162342

2 Answers

4
votes

The compiler needs to be able to deduce the type of the argument in some way, this can happen through explicit type annotations as in num: i32 or through contextual information such as

fn use_some_closure() {
    let expensive_closure = |num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        num
    };
    expensive_closure(42);
}

Without annotation or usage there's no way to figure out what num is.

Playground

4
votes

the book, but also the reference specify that theres no annotations needed, yet I am getting this error.

No, the key word of the book and the reference is required, which is different from needed. Something can ben contextually needed even when it's not generally required.

For closure the distinction is in opposition to "static functions" (fn) for which annotations are a syntactic requirement: you can not write valid static functions without providing type annotations, whereas generally speaking you can write closures without type annotations.

However the compiler still needs to know the concrete type of the closure, which requires being able to infer the parameter & return types. If it can not because there are not enough constraints, it will complain and need explicitly specified types.

In your example, there is nothing constraining the type of num, so rustc has no way to know what the concrete type of num is, and therefore is not able to infer what the concrete type of the closure should be.

But in most cases there is e.g.

let it = repeat(5).map(|x| x+1);

the compiler is happy with that, because the input and output types of the closure are necessarily what map provides, which is Repeat::Item, which in this case is i32 (because that's what integer literals default to barring other constraints).