There is no way in Rust to define a struct that inherits the parent
struct’s fields and method implementations.
You choose inheritance for two main reasons:
reuse of code
you can share Rust code using default trait method
implementations instead
polymorphism
Inheritance has recently fallen out of favor because it’s often at
risk of sharing more code than necessary.
Rust takes a different approach, using trait objects instead of
inheritance.
Using traits
Defining a trait for common behavior
In Rust, we refrain from calling structs and enums “objects” to
distinguish them from other languages’ objects. In a struct or
enum, the data in the struct fields and the behavior in impl
blocks are separated, whereas in other languages, the data and
behavior combined into one concept is often labeled an object.
However, trait objects are more like objects in other languages in
the sens that they combine data and behavior. But trait objects
differ from traditional objects in that we can’t add data to a
trait object. Trait objects aren’t as generally useful as objects
in other languages: their specific purpose is to allow abstraction
across common behavior.
The advantage of using trait objects and Rust’s type system to
write code similar to code using duck typing is that we never have
to check whether a value implements a particular method at runtime
or worry about getting errors if a value doesn’t implement a method
but we call it anyway. Rust won’t compile our code if the values
don’t implement the traits that the trait objects need.
Trait objects perform dynamic dispatch
When the compiler can’t tell at compile time which method you’re
calling. It’s a trade-off to consider.
Object safety is required for trait objects
A trait is object safe if the methods defined in the trait have the
following properties:
the return type isn’t self
there are no generic type parameter
Implementing an object-oriented design pattern
State pattern example:
By implementing the state pattern exactly as it’s defined for OOP,
we’re not taking as full advantage of Rust’s strengths as we could.
Encoding states and behavior as types
Advantage: invalid states are now impossible because of the type
system and the type checking that happens at compile time.
OOP patterns won’t always be the best solution in Rust due to
certain features, like ownership, that OOP don’t have.
You can use trait objects to get some object-oriented features in
Rust. Dynamic dispatch can give your code some flexibility in
exchange for a bit of runtime performance.