Hello! Welcome to the final lesson of our short course on Rust traits.
In our previous lessons, we've covered the first two essential steps:
- Defining a trait: We created a blueprint for behavior, like the
Drawabletrait with itsdrawmethod signature. - Implementing a trait: We wrote the specific code for a struct to fulfill that blueprint, using an
impl Trait for Typeblock.
Today, we'll complete the picture. This lesson is about putting all that work to use. You'll learn how to instantiate a struct and call a method from its implemented trait. By the end of this session, you'll be able to take a type that implements a trait, create an object from it, and actually use the shared behavior you've defined. This is the payoff that makes traits so powerful.
Putting It All Together: Instantiation and Calling
You've already defined a trait and implemented it. The final step is surprisingly straightforward. Once a trait is implemented for a struct, the trait's methods become available on instances of that struct, just as if they were regular methods defined directly on the struct itself.
The process is two-fold:
- Instantiate the struct: You create an instance of your struct just like you normally would.
- Call the method: You use dot notation (
.) on the instance to call the method from the trait.
Let's watch a short video that demonstrates this final step. It continues with the Summary trait example we've seen before, creating instances of NewsArticle and SocialPost and then calling the summarize method on them.
64: Traits in Rust are Awesome
This clip from 'Traits in Rust are Awesome' by Rustfully shows how to create struct instances and call the methods provided by their implemented trait.
Watch from 02:12 to 03:00. Notice how article and post are created, and then how the .summarize() method is called on each one. The syntax is identical to calling a standard struct method.
As you saw in the video, after all the setup of defining and implementing the trait, using it is as simple as:
// 1. Instantiate the struct
let article = NewsArticle { ... };
// 2. Call the trait method on the instance
println!("{}", article.summarize());
This seamless integration is a key design feature of Rust. The compiler knows that NewsArticle implements Summary, so it makes the summarize method available on any NewsArticle instance.
A Complete, Self-Contained Example
To help solidify all three steps we've covered in this course, let's look at one complete, practical example that shows defining, implementing, and using a trait all in one place.
The following resource provides a Shape trait with two structs, Circle and Rectangle, that implement it.
Mastering Rust Traits: 15 Practical Examples That Will ...
This example from the article 'Mastering Rust Traits' on Medium provides a perfect, compact demonstration of the entire trait workflow.
Focus on the code block under '1. Shape Trait — Basic Geometry Abstraction'. Trace the code's logic from top to bottom: See the Shape trait definition. See the impl Shape for Circle and impl Shape for Rectangle blocks. Finally, look inside the main function to see how the circle and rectangle instances are created and how their trait methods (name, area, perimeter) are called.
This Shape example is a classic use case for traits. It lets you define a common interface for a group of related types, enabling you to treat them uniformly while respecting their individual differences in behavior.
Your Turn: Putting It All into Practice
Now, let's do one final exercise to put your knowledge to the test. Below are the definitions and implementations for an Animal trait and two structs, Dog and Cat.
Your task is to write the main function to make the code run and produce the expected output.
// Trait definition
trait Animal {
fn speak(&self) -> String;
}
// Structs
struct Dog;
struct Cat;
// Implementations
impl Animal for Dog {
fn speak(&self) -> String {
"Woof!".to_string()
}
}
impl Animal for Cat {
fn speak(&self) -> String {
"Meow!".to_string()
}
}
// YOUR TASK: Write the main function here.
// It should:
// 1. Create an instance of a Dog.
// 2. Print what the dog says by calling its `speak` method.
// 3. Create an instance of a Cat.
// 4. Print what the cat says by calling its `speak` method.
fn main() {
// Your code goes here!
}
Copy the code above into an editor or the Rust Playground and complete the main function.
Test your understanding!
Here is the completed main function. How does your solution compare?
Show answer
fn main() {
// 1. Create an instance of a Dog.
let my_dog = Dog;
// 2. Print what the dog says.
println!("The dog says: {}", my_dog.speak());
// 3. Create an instance of a Cat.
let my_cat = Cat;
// 4. Print what the cat says.
println!("The cat says: {}", my_cat.speak());
}
This main function follows the pattern exactly: it instantiates each struct and then calls the speak method from the Animal trait on each instance. The output will be:
The dog says: Woof!
The cat says: Meow!
Conclusion and Next Steps
Congratulations! You have successfully completed this course and now understand the full, fundamental workflow of using traits in Rust.
Key Takeaways from this Lesson:
- To use a trait method, you first instantiate the struct that implements it.
- You then call the method using dot notation (
instance.method()) just like any other method. - Traits allow different types to share method names while having unique, type-specific behavior.
Course Recap:
Over these three lessons, we've covered the core cycle of traits:
- Defining a shared interface with
trait. - Implementing that interface for a concrete type with
impl Trait for Type. - Using the shared behavior by creating an instance and calling the methods.
You now have a solid foundation in one of Rust's most important and powerful features.
Where to Go from Here?
This is just the beginning. If you're curious to learn more, here are some topics that build directly on what you've learned:
- Traits as Parameters: Writing functions that accept any type that implements a particular trait (e.g.,
fn print_summary(item: &impl Summary)). - Trait Bounds: A more general way of using traits with generic type parameters.
- Standard Library Traits: Exploring common traits provided by Rust itself, such as
Display(for custom printing),Debug(for developer-focused printing), andClone(for creating copies of objects).
Thank you for taking this course. Happy coding in Rust