Bird
Raised Fist0
Rustprogramming~20 mins

Trait objects overview in Rust - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Rust Trait Objects Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Rust code using a trait object?

Consider the following Rust code that uses a trait object to call a method on different types:

Rust
trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;

impl Speak for Dog {
    fn speak(&self) -> String {
        String::from("Woof")
    }
}

impl Speak for Cat {
    fn speak(&self) -> String {
        String::from("Meow")
    }
}

fn animal_speak(animal: &dyn Speak) {
    println!("{}", animal.speak());
}

fn main() {
    let dog = Dog;
    let cat = Cat;
    animal_speak(&dog);
    animal_speak(&cat);
}
AWoof\nMeow
BMeow\nMeow
CWoof\nWoof
DMeow\nWoof
Attempts:
2 left
💡 Hint

Remember that the trait object calls the method implemented for the actual type.

🧠 Conceptual
intermediate
1:30remaining
What is a key limitation of trait objects in Rust?

Which of the following is a limitation when using trait objects in Rust?

ATrait objects can be copied freely without ownership concerns.
BTrait objects allow storing multiple types without any restrictions.
CTrait objects cannot be used with traits that have generic methods.
DTrait objects require the trait to be implemented only for primitive types.
Attempts:
2 left
💡 Hint

Think about what kind of methods can be called through a trait object.

🔧 Debug
advanced
2:30remaining
Why does this Rust code fail to compile when using a trait object?

Examine the code below and identify why it fails to compile:

Rust
trait Draw {
    fn draw(&self);
    fn resize<T>(&self, scale: T);
}

struct Circle;

impl Draw for Circle {
    fn draw(&self) {
        println!("Drawing a circle");
    }
    fn resize<T>(&self, scale: T) {
        println!("Resizing circle");
    }
}

fn paint(shape: &dyn Draw) {
    shape.draw();
}

fn main() {
    let c = Circle;
    paint(&c);
}
AThe method draw is missing a return type, causing a compilation error.
BThe trait Draw is not object safe because it has a generic method, so it cannot be used as a trait object.
CThe struct Circle does not implement the Draw trait correctly because it lacks a constructor.
DThe function paint requires ownership of the shape, but a reference is provided.
Attempts:
2 left
💡 Hint

Check the trait methods and their signatures for object safety rules.

📝 Syntax
advanced
1:30remaining
Which option correctly creates a boxed trait object in Rust?

Given the trait Speak and struct Dog implementing it, which code snippet correctly creates a boxed trait object?

Rust
trait Speak {
    fn speak(&self) -> String;
}

struct Dog;

impl Speak for Dog {
    fn speak(&self) -> String {
        String::from("Woof")
    }
}

fn main() {
    // Which line correctly creates a boxed trait object?
}
Alet pet: Box<dyn Speak> = Dog::new();
Blet pet: Box<Speak> = Box::new(Dog);
Clet pet: Box<dyn Speak> = Box::new(&Dog);
Dlet pet: Box<dyn Speak> = Box::new(Dog);
Attempts:
2 left
💡 Hint

Remember the syntax for trait objects and boxing in Rust.

🚀 Application
expert
2:00remaining
How many items are in the vector after this Rust code runs?

Consider this Rust code that stores different types implementing a trait in a vector of trait objects:

Rust
trait Animal {
    fn name(&self) -> &str;
}

struct Dog;
struct Cat;

impl Animal for Dog {
    fn name(&self) -> &str { "Dog" }
}

impl Animal for Cat {
    fn name(&self) -> &str { "Cat" }
}

fn main() {
    let mut animals: Vec<Box<dyn Animal>> = Vec::new();
    animals.push(Box::new(Dog));
    animals.push(Box::new(Cat));
    animals.push(Box::new(Dog));
    animals.push(Box::new(Cat));
    animals.pop();
    animals.push(Box::new(Dog));
    println!("Number of animals: {}", animals.len());
}
A4
B2
C5
D3
Attempts:
2 left
💡 Hint

Count the pushes and pops carefully to find the final length.

Practice

(1/5)
1. What is the main purpose of using trait objects in Rust?
easy
A. To allow different types to be used through a common interface at runtime
B. To improve compile-time performance by avoiding dynamic dispatch
C. To create new data types that do not implement any traits
D. To statically bind methods to specific types only

Solution

  1. Step 1: Understand trait objects concept

    Trait objects let you use different types that implement the same trait through a common interface.
  2. Step 2: Identify dynamic dispatch role

    Trait objects enable dynamic dispatch, meaning method calls are decided at runtime, allowing flexibility.
  3. Final Answer:

    To allow different types to be used through a common interface at runtime -> Option A
  4. Quick Check:

    Trait objects = common interface + runtime dispatch [OK]
Hint: Trait objects enable runtime method calls on different types [OK]
Common Mistakes:
  • Confusing trait objects with static dispatch
  • Thinking trait objects create new unrelated types
  • Believing trait objects improve compile-time speed
2. Which of the following is the correct syntax to create a trait object reference for a trait named Animal?
easy
A. let a: &Animal = &dog;
B. let a: Animal = &dog;
C. let a: dyn Animal = dog;
D. let a: &dyn Animal = &dog;

Solution

  1. Step 1: Recall trait object syntax

    Trait objects require the dyn keyword before the trait name when used as a reference or pointer.
  2. Step 2: Check each option

    let a: &dyn Animal = &dog; uses &dyn Animal, which is the correct syntax for a trait object reference.
  3. Final Answer:

    let a: &dyn Animal = &dog; -> Option D
  4. Quick Check:

    Trait object syntax = &dyn Trait [OK]
Hint: Use &dyn Trait for trait object references [OK]
Common Mistakes:
  • Omitting the dyn keyword
  • Trying to use trait name without reference
  • Assigning trait object without pointer or reference
3. What will be the output of the following Rust code?
trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
impl Speak for Dog {
    fn speak(&self) -> String {
        "Woof".to_string()
    }
}

struct Cat;
impl Speak for Cat {
    fn speak(&self) -> String {
        "Meow".to_string()
    }
}

fn animal_speak(animal: &dyn Speak) {
    println!("{}", animal.speak());
}

fn main() {
    let dog = Dog;
    let cat = Cat;
    animal_speak(&dog);
    animal_speak(&cat);
}
medium
A. Woof\nMeow
B. Dog\nCat
C. Woof\nWoof
D. Compilation error due to trait object usage

Solution

  1. Step 1: Understand trait implementations

    Dog and Cat both implement the Speak trait with their own speak() returning "Woof" and "Meow" respectively.
  2. Step 2: Analyze function calls with trait objects

    animal_speak takes a reference to a dyn Speak trait object and calls speak(), which uses dynamic dispatch to call the correct method.
  3. Final Answer:

    Woof\nMeow -> Option A
  4. Quick Check:

    Dynamic dispatch calls correct speak() = Woof then Meow [OK]
Hint: Trait objects call correct method at runtime [OK]
Common Mistakes:
  • Expecting static dispatch output
  • Confusing struct names with method output
  • Thinking code causes compilation error
4. Identify the error in the following Rust code using trait objects:
trait Draw {
    fn draw(&self);
}

struct Circle;
impl Draw for Circle {
    fn draw(&self) {
        println!("Drawing Circle");
    }
}

fn main() {
    let c = Circle;
    let obj: Box<Draw> = Box::new(c);
    obj.draw();
}
medium
A. Circle does not implement Draw trait
B. Missing dyn keyword in Box type declaration
C. Cannot call draw() on Box pointer
D. Box::new() requires a reference, not value

Solution

  1. Step 1: Check trait object syntax in Box

    Trait objects require the dyn keyword when used as a pointer type like Box.
  2. Step 2: Identify missing dyn keyword

    The code uses Box<Draw> instead of Box, causing a syntax error.
  3. Final Answer:

    Missing dyn keyword in Box type declaration -> Option B
  4. Quick Check:

    Box trait object needs dyn keyword [OK]
Hint: Always use dyn with trait objects in pointers like Box [OK]
Common Mistakes:
  • Omitting dyn keyword in trait object types
  • Assuming trait implementation is missing
  • Thinking Box cannot call trait methods
5. You want to store different shapes (Circle, Square) in a single vector and call their area() method at runtime. Which approach correctly uses trait objects to achieve this?
trait Shape {
    fn area(&self) -> f64;
}

struct Circle { radius: f64 }
struct Square { side: f64 }

impl Shape for Circle {
    fn area(&self) -> f64 { 3.14 * self.radius * self.radius }
}

impl Shape for Square {
    fn area(&self) -> f64 { self.side * self.side }
}

fn main() {
    // Fill in the blank
    let shapes: Vec> = vec![
        Box::new(Circle { radius: 2.0 }),
        Box::new(Square { side: 3.0 }),
    ];

    for shape in shapes.iter() {
        println!("Area: {}", shape.area());
    }
}
hard
A. Use Vec<&Shape> with references to shapes without Box
B. Use Vec<Shape> directly without pointers
C. Use Vec> with Box::new for each shape
D. Use Vec without Box or references

Solution

  1. Step 1: Understand trait object storage

    Trait objects must be stored behind pointers like Box or references because their size is unknown at compile time.
  2. Step 2: Analyze vector type and initialization

    Using Vec> with Box::new() for each shape correctly stores different types implementing Shape.
  3. Final Answer:

    Use Vec> with Box::new for each shape -> Option C
  4. Quick Check:

    Trait objects need pointers like Box in collections [OK]
Hint: Store trait objects in Box pointers inside collections [OK]
Common Mistakes:
  • Trying to store trait objects directly without pointers
  • Using Vec<Shape> which is invalid
  • Using references without ensuring lifetime
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard