diff --git a/src/ch18-02-trait-objects.md b/src/ch18-02-trait-objects.md index 71c64644a1..341b0b4b30 100644 --- a/src/ch18-02-trait-objects.md +++ b/src/ch18-02-trait-objects.md @@ -225,7 +225,7 @@ didn’t mean to pass and so should pass a different type, or we should implemen ### Trait Objects and Type Inference -One downside to using trait objects is how they interact with type inference. +One downside to using trait objects is how they interact with type inference. For example, consider type inference for `Vec`. When `T` is not a trait object, Rust just needs to know the type of a single element in the vector to infer `T`. So an empty vector causes a type inference error: @@ -246,8 +246,8 @@ let v = vec!["Hello world"]; # } ``` -Type inference is trickier for trait objects. For example, say we tried to factor -the `components` array in Listing 17-9 into a separate variable, like this: +Type inference is trickier for trait objects. For example, say we tried to factor +the `components` array in Listing 18-9 into a separate variable, like this: ```rust,ignore,does_not_compile fn main() { @@ -260,7 +260,7 @@ fn main() { } ``` -Listing 17-11: Factoring the components array causes a type error +Listing 18-11: Factoring the components array causes a type error This refactor causes the program to no longer compile! The compiler rejects this program with the following error: @@ -280,26 +280,26 @@ error[E0308]: mismatched types | |_____^ expected `SelectBox`, found `Button` ``` -In Listing 17-09, the compiler understands that the `components` vector must have the type -`Vec>` because that's specified in the `Screen` struct definition. But in Listing 17-11, +In Listing 18-09, the compiler understands that the `components` vector must have the type +`Vec>` because that's specified in the `Screen` struct definition. But in Listing 18-11, the compiler loses that information at the point where `components` is defined. To fix the issue, you have to give a hint to the type inference algorithm. That can either be via an explicit cast on any element of the vector, like this: ```rust,ignore - let components = vec![ - Box::new(SelectBox { /* .. */ }) as Box, - Box::new(Button { /* .. */ }), - ]; +let components = vec![ + Box::new(SelectBox { /* .. */ }) as Box, + Box::new(Button { /* .. */ }), +]; ``` Or it can be via a type annotation on the let-binding, like this: ```rust,ignore - let components: Vec> = vec![ - Box::new(SelectBox { /* .. */ }), - Box::new(Button { /* .. */ }), - ]; +let components: Vec> = vec![ + Box::new(SelectBox { /* .. */ }), + Box::new(Button { /* .. */ }), +]; ``` In general, it is good to be aware that using trait objects can cause a worse developer experience for @@ -307,7 +307,6 @@ API clients in the case of type inference. - ### Trait Objects Perform Dynamic Dispatch Recall in [“Performance of Code Using @@ -329,7 +328,7 @@ call. This lookup incurs a runtime cost that doesn’t occur with static dispatc Dynamic dispatch also prevents the compiler from choosing to inline a method’s code, which in turn prevents some optimizations, and Rust has some rules, called _dyn compatibility_, about where you can and cannot use dynamic dispatch. Those -rules are beyond the scope of this discussion, but you can read more about them +rules are beyond the scope of this discussion, but you can read more about them [in the reference][dyn-compatibility]. However, we did get extra flexibility in the code that we wrote in Listing 18-5 and were able to support in Listing 18-9, so it’s a trade-off to consider.