About Box, Dyn and clone_box in Rust
The lengths you have to go to for object-orientation in Rust ....
Git repo: https://github.com/caveofprogramming/rust/
For many of us, writing Rust in an object-oriented style would seem natural, since we’re used to Java and Python and what-not.
But Rust does make you jump through a few hoops, for the sake of efficiency.
In this post we’ll see how to get object oriented behaviour in Rust, even when we want to be able to clone a vector of objects, which is sometimes very useful.
First let’s start with a simple trait.
Anything that implements this trait must have a get method that returns a float.
Now we’ll create a struct that implements the trait.
I’ve implemented the trait for Pi, and I’ve also added a constructor.
Now we can use Pi like this:
This prints:
I can also add Pi to vectors:
This works fine.
However, there’s a problem if I change the type of the vector to Vec<Value>, intending to put other things that implement the Value trait into the vector.
This doesn’t work:
The problem is that Rust, for efficiency, wants to know the size of everything you put in a vector, and here it doesn’t know that. We could create other things of difference sizes that implement Value, even at runtime, and put them in the vector.
The values in the vector will just be stored in contiguous blocks of memory, which can’t work if Rust doesn’t even know the size of them.
Furthermore, we don’t get the polymorphic behaviour we expect. We want the correct get method to be called, depending on what objects are found in the vector.
We can fix the first issue by storing an array of pointers, so that the actual objects are stored on the heap. To make polymorphism work, we need to use the dyn keyword.
We end up with the following working code:
By wrapping the vector elements in a Box and by using the dyn keyword, we get the result we expect.
Now suppose we want to clone the entire vector for some reason.
The following code still doesn’t work.
Rust knows how to clone the vector; it just doesn’t know how to clone
Box<dyn Value>
To fix this, we have to implement Clone for Box<dyn Value>.
The following implementation would work if we only ever expected Pi to implement Value (which is obviously a bit silly).
Now the program runs, but the problem is that when we clone a Vector of Value objects, we’re always going to get a Vector of Pi.
The solution is to give each implementation of Value a method which returns a box containing the cloned version of itself.
An easy way to make Pi cloneable is just to add #[derive(Clone)]at the top of it. But we could alternatively implement Clone for Pi however we want.
Now we add a method to the Value trait called clone_box.
Then we implement this for Pi.
Finally, we use this in our implementation of Clone for Box<dyn Value>.
Now our program works properly.
We can create something else that implements Value.
Now we can add Surprise to our vector and everything still works correctly.
When we run the program, the contents of both the original vector and the cloned vector behave appropriately.


















