Returning Types with Traits
Part of the Object Oriented Programming section of Coddy's Rust journey. Lesson 43 of 61.
You've used trait bounds to constrain what types a function can accept. But what about what a function returns? The impl Trait syntax lets you specify that a function returns "some type that implements this trait" without naming the concrete type.
Here's the syntax in action:
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
headline: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
self.headline.clone()
}
}
fn create_summary() -> impl Summary {
Article { headline: String::from("Breaking News!") }
}
The return type impl Summary tells callers "you'll get something that implements Summary." The caller can use any method from the trait, but doesn't need to know the actual type is Article.
This is particularly useful when the concrete type is complex or when you want to hide implementation details. The function promises a capability (the trait), not a specific type.
However, there's an important limitation: the function must return exactly one concrete type. You cannot conditionally return different types that implement the same trait. That requires trait objects, which you'll learn about later.
// This works - always returns Article
fn make_item() -> impl Summary {
Article { headline: String::from("Hello") }
}
// This would NOT compile - two different types
// fn make_item(flag: bool) -> impl Summary {
// if flag { Article { ... } } else { Tweet { ... } }
// }
Challenge
EasyLet's build a greeting card factory that uses the impl Trait return type to hide implementation details! You'll create a function that returns "something that can greet" without revealing the concrete type to the caller.
You'll organize your code across two files:
greetings.rs: Define a publicGreettrait with agreetmethod that takes&selfand returns aString. Then create aCardstruct (it doesn't need to be public!) with amessagefield (String). Implement theGreettrait forCard, returning the message. Finally, create a public function calledcreate_greetingthat takes aStringparameter and returnsimpl Greet. This function should create and return aCardwith the given message.main.rs: Bring in your greetings module and use the input provided to callcreate_greeting. The beauty here is that your main file doesn't know about theCardtype at all. It only knows it received something that implementsGreet. Call thegreetmethod on the returned value and print the result.
The key insight is that Card stays private to the module, but callers can still use it through the trait interface. The function promises a capability (greeting), not a specific type.
Your output should display the greeting:
{message}For example, with input Happy Birthday!:
Happy Birthday!And with input Congratulations on your promotion!:
Congratulations on your promotion!You will receive one input: the greeting message.
Try it yourself
mod greetings;
use greetings::Greet;
fn main() {
// Read the greeting message from input
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Call create_greeting with the message
// Note: You don't know the concrete type - only that it implements Greet!
// TODO: Call the greet method and print the result
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Methods and Behavior
Intro Implementation BlocksThe Self ParameterMutable MethodsAssociated FunctionsMultiple Implementation BlocksMethod ChainingRecap - Rectangle Actions4Project: Virtual Pet
Defining the PetFeeding the Pet7Standard Traits
The Debug TraitThe Display TraitClone and CopyEquality TraitsRecap - Printable Point10Project: Document System
The Draw TraitText Component2Encapsulation and Modules
Modules BasicsThe Public KeywordPrivate FieldsGettersSettersRecap - Secure Locker5Generics
Generic StructsGeneric MethodsMultiple Generic TypesGeneric FunctionsRecap - Coordinate Point8Traits as Bounds
Trait Bounds SyntaxMultiple BoundsThe Where ClauseReturning Types with TraitsRecap - Generic Printer11Design Patterns in Rust
Newtype PatternCompositionThe Drop TraitFrom and IntoRecap - Smart Pointer MockPractice on your own: Online Rust compiler