diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 1969ed05a5..8b27814ce4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -133,6 +133,7 @@ - [Traits](trait.md) - [Derive](trait/derive.md) + - [Returning Traits with `dyn`](trait/dyn.md) - [Operator Overloading](trait/ops.md) - [Drop](trait/drop.md) - [Iterators](trait/iter.md) diff --git a/src/trait/dyn.md b/src/trait/dyn.md new file mode 100644 index 0000000000..5b2f8c2f3e --- /dev/null +++ b/src/trait/dyn.md @@ -0,0 +1,47 @@ +# Returning Traits with `dyn` + +The Rust compiler needs to know how much space every function's return type requires. This means all your functions have to return a concrete type. Unlike other languages, if you have a trait like `Animal`, you can't write a function that returns `Animal`, because its different implementations will need different amounts of memory. + +However, there's an easy workaround. Instead of returning a trait object directly, our functions return a `Box` which _contains_ some `Animal`. A `box` is just a reference to some memory in the heap. Because a reference has a statically-known size, and the compiler can guarantee it points to a heap-allocated `Animal`, we can return a trait from our function! + +Rust tries to be as explicit as possible whenever it allocates memory on the heap. So if your function returns a pointer-to-trait-on-heap in this way, you need to write the return type with the `dyn` keyword, e.g. `Box`. + +```rust,editable +struct Sheep {} +struct Cow {} + +trait Animal { + // Instance method signature + fn noise(&self) -> &'static str; +} + +// Implement the `Animal` trait for `Sheep`. +impl Animal for Sheep { + fn noise(&self) -> &'static str { + "baaaaah!" + } +} + +// Implement the `Animal` trait for `Cow`. +impl Animal for Cow { + fn noise(&self) -> &'static str { + "moooooo!" + } +} + +// Returns some struct that implements Animal, but we don't know which one at compile time. +fn random_animal(random_number: f64) -> Box { + if random_number < 0.5 { + Box::new(Sheep {}) + } else { + Box::new(Cow {}) + } +} + +fn main() { + let random_number = 0.234; + let animal = random_animal(random_number); + println!("You've randomly chosen an animal, and it says {}", animal.noise()); +} + +``` \ No newline at end of file