Even without data it is a bit complicated, and Rust does not use this type of pattern very much. This is because Rust has strict rules on borrowing and ownership, as you know. But if you want to start a list like this (a linked list), `Box` can help.
## Box around traits
`Box` is very useful for returning traits. You know that you can write traits in generic functions like in this example:
```rust
use std::fmt::Display;
struct DoesntImplementDisplay {}
fn displays_it<T:Display>(input: T) {
println!("{}", input);
}
fn main() {}
```
This only takes something with `Display`, so it can't accept our struct `DoesntImplementDisplay`. But it can take in a lot of others like `String`.
You also saw that we can use `impl Trait` to return other traits, or closures. `Box` can be used in a similar way. You can use a `Box` because otherwise the compiler won't know the size of a value. This example shows that a trait can be used on something of any size:
```rust
#![allow(dead_code)] // Tell the compiler to be quiet
use std::mem::size_of; // This gives the size of a type
trait JustATrait {} // We will implement this on everything
enum EnumOfNumbers {
I8(i8),
AnotherI8(i8),
OneMoreI8(i8),
}
impl JustATrait for EnumOfNumbers {}
struct StructOfNumbers {
an_i8: i8,
another_i8: i8,
one_more_i8: i8,
}
impl JustATrait for StructOfNumbers {}
enum EnumOfOtherTypes {
I8(i8),
AnotherI8(i8),
Collection(Vec<String>),
}
impl JustATrait for EnumOfOtherTypes {}
struct StructOfOtherTypes {
an_i8: i8,
another_i8: i8,
a_collection: Vec<String>,
}
impl JustATrait for StructOfOtherTypes {}
struct ArrayAndI8 {
array: [i8; 1000], // This one will be very large
an_i8: i8,
in_u8: u8,
}
impl JustATrait for ArrayAndI8 {}
fn main() {
println!(
"{}, {}, {}, {}, {}",
size_of::<EnumOfNumbers>(),
size_of::<StructOfNumbers>(),
size_of::<EnumOfOtherTypes>(),
size_of::<StructOfOtherTypes>(),
size_of::<ArrayAndI8>(),
);
}
```
When we print the size of these, we get `2, 3, 32, 32, 1002`. So if you were to do this, it would give an error:
```rust
// ⚠️
fn returns_just_a_trait() -> JustATrait {
let some_enum = EnumOfNumbers::I8(8);
some_enum
}
```
It says:
```text
error[E0746]: return type cannot have an unboxed trait object
--> src\main.rs:53:30
|
53 | fn returns_just_a_trait() -> JustATrait {
| ^^^^^^^^^^ doesn't have a size known at compile-time
```
And this is true, because the size could be 2, 3, 32, 1002, or anything else. So we put it in a `Box` instead. Here we also add the keyword `dyn`. `dyn` is a word that shows you that you are talking about a trait, not a struct or anything else.
So you can change the function to this:
```rust
// 🚧
fn returns_just_a_trait() -> Box<dynJustATrait> {
let some_enum = EnumOfNumbers::I8(8);
Box::new(some_enum)
}
```
And now it works, because on the stack is just a `Box` and we know the size of `Box`.
You see this a lot in the form `Box<dyn Error>`, because sometimes you can have more than one possible error.
We can quickly create two error types to show this. To make an official error type, you have to implement `std::error::Error` for it. That part is easy: just write impl `std::error::Error {}`. But errors also need `Debug` and `Display` so they can give information on the problem. `Debug` is easy with `#[derive(Debug)]` but `Display` needs the `.fmt()` method. We did this once before.
The code looks like this:
```rust
use std::error::Error;
use std::fmt;
#[derive(Debug)]
struct ErrorOne;
impl Error for ErrorOne {} // Now it is an error type with Debug. Time for Display:
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
```
This is not surprising, because we know that a trait can work on many things, and they each have different sizes.
## Default and the builder pattern
You can implement a trait called `Default` that will give values to a `struct` or `enum` that you think will be most common. The builder pattern works nicely with this to let users easily make changes when they want. First let's look at `Default`. Actually, most general types in Rust already have `Default`, and they are not surprising: 0, empty strings, `false`, etc.