What is the effect of writing the value of the option when returning the closure?
let value = Some(0);
let closure = if value.is_some() {
|value: i32| false
} else {
|value: i32| true
};
The code above does not produce a compilation error However, the code below has a compilation error What's the reason?
let closure = if let Some(option_value) = value {
|value: i32| option_value == value
} else {
|value: i32| true
};
They're all different types
`if` and `else` have incompatible types
no two closures, even if identical, have the same type
consider boxing your closure and/or using it as a trait object
let closure = if let Some(option_value) = value {
Box::new(move |value: i32| option_value == value)
} else {
Box::new(|value: i32| true)
};
Box is a solution. But I don't know the difference yet
As baseline, every function (anonymous or not) has its own concrete type, different from all others.
However named functions and non-closure anonymous functions can be coerced to "function pointers" fn(args...) -> ret
.
That is what happens in your first snippet, if you use "the unit trick":
let _: () = closure;
to know what rustc has decided the concrete type of closure
is, it tells you:
found fn pointer `fn(i32) -> bool`
so because both anonymous functions are static (they don't actually close over anything), the compiler converted both into function pointers.
That doesn't work with the second snippet, because the first branch creates an actual closure, which can't be converted to a function pointer (because it's not just a function, it's also data). Hence type mismatch.
Boxing works, because it allows the creation of dynamically dispatched trait objects of type
Box<dyn Fn(i32) -> bool>
which are compatible.