Reputation: 555
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?
Upvotes: 2
Views: 569
Reputation: 42227
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).
Upvotes: 5
Reputation: 2618
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.
Upvotes: 5