Menu
Coddy logo textTech

What is a Trait?

Part of the Object Oriented Programming section of Coddy's Rust journey — lesson 29 of 61.

Generics let you write code that works with any type, but sometimes you need to guarantee that a type can do something specific. This is where traits come in.

A trait defines a set of methods that a type must implement. Think of it as a contract—any type that "signs" this contract promises to provide the specified behavior. If you've used interfaces in other languages, traits serve a similar purpose.

Here's how you define a trait:

trait Describable {
    fn describe(&self) -> String;
}

The trait keyword introduces the trait, followed by its name. Inside the curly braces, you declare method signatures—just the name, parameters, and return type, with no body. The semicolon after the signature indicates that this is a requirement, not an implementation.

This Describable trait says: "Any type that implements me must provide a describe method that takes a reference to itself and returns a String." The trait doesn't care how the method works—that's up to each type that implements it.

Traits become powerful when multiple different types implement the same trait. A Book, a Car, and a Person could all be Describable, each providing their own unique description. The trait guarantees they all share this common capability.

challenge icon

Challenge

Easy

Let's define your first trait! A trait establishes a contract—a promise that any type implementing it will provide specific behavior. You'll create a Summarizable trait that different types can implement to provide a summary of themselves.

You'll organize your code across two files:

  • summary.rs: Define a public trait called Summarizable with a single method signature: summarize(&self) -> String. Remember, in a trait definition you only declare the method signature with a semicolon—no body. This tells Rust "any type that implements this trait must provide a summarize method that returns a String."
  • main.rs: Bring in your summary module and print a message confirming your trait is defined. Since we haven't yet learned how to implement traits (that's the next lesson!), you'll simply verify your trait compiles correctly.

In your main file, print the following message to confirm your trait definition is valid:

Summarizable trait defined successfully!

This challenge focuses purely on trait definition syntax—the trait keyword, the trait name, and declaring method signatures without implementations. In the next lesson, you'll learn how to make structs implement this trait!

Cheat sheet

A trait defines a set of methods that a type must implement. It acts as a contract that guarantees a type provides specific behavior.

To define a trait, use the trait keyword followed by the trait name and method signatures:

trait Describable {
    fn describe(&self) -> String;
}

Method signatures in traits include the name, parameters, and return type, but no body. The semicolon indicates this is a requirement for implementing types.

Multiple different types can implement the same trait, each providing their own implementation of the required methods.

Try it yourself

mod summary;

fn main() {
    // TODO: Print the confirmation message that the trait is defined
    // Expected output: "Summarizable trait defined successfully!"
    
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming