warning: trait objects without an explicit `dyn` are deprecated
--> src/main.rs:4:24
|
4 | let multiply_ref: &Fn(i32) -> i32 = &multiply;
| ^^^^^^^^^^^^^^ help: use `dyn`: `dyn Fn(i32) -> i32`
|
= note: `#[warn(bare_trait_objects)]` on by default
Fn(...) -> ... is a trait, and traits are not type. To use the trait object with dynamic dispatch you should attach the dyn keyword before the trait name. So this should work without warning.
let factor = 2;
let multiply = |a| a * factor;
let multiply_ref: &dyn Fn(i32) -> i32 = &multiply;
To generalize @Hyeonu‘s solution a bit: If your code has multiple errors (or warnings) in it, the compiler will often be able to spot only one of them at a time.
When you make a change to fix one error and get a brand-new error back, it’s usually a good idea to press forward with trying to fix the new error without reversing your original change. If your proposed fix didn’t work, the original error will eventually show up again on its own.
The chain of errors can sometimes be long, but there’s a correct program at the end of it somewhere.
This seems oddly common, unfortunately. I've seen a bunch of cases on Discord where the fix for a problem was "compile in the terminal so you can see the awesome error that rustc is generating rather than just the bit the IDE is showing".
You can think of dyn as "an operator that turns a trait into a type". That resulting type will be a DST, but it's not the DST-ness that's why it needed dyn.
Here's what I got from what you said: dyn will turn the Trait into a Dynamically Sized Type, or, as you said DST, when used in conjunction with a trait it will tell Rust that the type doesn't have a compile time known size.
I understood most of what you said, but the last part seems weird to me.
"but it's not the DST-ness that's why it needed dyn."
If A is a trait (and meets certain requirements for "object safety"), then dyn A is a type. This type can hold any value of any T such that T: A. But -- conceptually -- as soon as you turn a value of type T into a value of type dyn A, the compiler no longer tracks the original type T. So given a value of type dyn A, it's not possible statically (= at compile time) to know its size, because A could be implemented by two types of different sizes, and the compiler doesn't know which of these types the value came from. A value of type dyn A is called a "trait object". Because the amount of memory needed to store a given dyn A value isn't known at compile time, Rust will not allocate such values on the stack (there's a way to do this but it's not currently exposed by the language), and in particular you can't have a variable of type dyn A. Instead, you have to store the dyn A value on the heap and keep a pointer of some kind (shared or exclusive reference, Box, Rc, ...).
dyn is only used in this context, to describe trait object types. Other types are likedyn A in that their values don't have a fixed statically-known size, but are not trait object types. An example (as @scottmcm said) is str, which can represent string data of arbitrary size. And as with dyn A, we must use indirection to work with values of these "unsized" types (so you can't have a variable of type str, you have to use &str or Box<str> or etc.).
In summary, dyn A where A is an object-safe trait is always an unsized type, but some unsized types are not of the form dyn A for any A, like str or [u8].