Complete these tasks to reinforce what you learned in this module.
Define a trait Describe with one method fn describe(&self) -> String. Implement it for a struct Dog with field name: String so that describe() returns format!("Dog named {}", self.name). In main, create a Dog, call describe(), and print the result.
name field. The theory shows trait definition and impl Trait for Type.// Task 1: Describe trait and Dog. See tasks/TASKS.md.
fn main() {
todo!("Define Describe, Dog, impl Describe for Dog, call describe()");
}
Write a generic function print_describe<T: Describe>(x: &T) that prints the result of x.describe(). Use the same Describe and Dog from Task 1 (or redefine them). Call print_describe with a Dog in main.
.describe() on x. The theory explains trait bounds with T: Trait.// Task 2: print_describe with trait bound. See tasks/TASKS.md.
fn main() {
todo!("Define Describe, Dog, print_describe<T: Describe>, call with Dog");
}
Define two newtype structs Celsius(i32) and Fahrenheit(i32). Implement From<Celsius> for Fahrenheit using the formula c * 9 / 5 + 32. Implement TryFrom<i32> for Celsius whose error is a String: return Err(format!("{value} is below absolute zero")) when value < -273, otherwise Ok(Celsius(value)). Write a function fn convert(raw: i32) -> Result<Fahrenheit, String> that builds a Celsius with Celsius::try_from(raw)? and then converts it with .into(). In main, call convert(100) and convert(-300), printing "{raw}C = {}F" (with the inner i32) on success and "error: {e}" on failure.
From and you get Into for free, so c.into() works once the target type is known. TryFrom returns a Result, so ? can early-return its error. The theory file theory/02_conversions.md covers From/Into and TryFrom.// Task 3: From / Into / TryFrom conversions. See tasks/TASKS.md.
fn main() {
todo!("Define Celsius/Fahrenheit, impl From + TryFrom, write convert(), print results");
}
The Shape trait and two types (Square, Rectangle) with area() are provided in the editor. In main, put a Square { side: 3 } and a Rectangle { w: 2, h: 4 } into a single Vec<Box<dyn Shape>>, then sum their areas and print total area = <sum>.
Vec<Box<dyn Shape>> can hold different concrete types behind the Shape trait — wrap each value in Box::new(...). Then shapes.iter().map(|s| s.area()).sum::<i32>(). (This is C#'s List<IShape>.) See theory/03_trait_objects.md.// Task 4: store different shapes in one Vec<Box<dyn Shape>> and sum their areas.
// See tasks/TASKS.md and theory/03_trait_objects.md.
trait Shape {
fn area(&self) -> i32;
}
struct Square {
side: i32,
}
struct Rectangle {
w: i32,
h: i32,
}
impl Shape for Square {
fn area(&self) -> i32 {
self.side * self.side
}
}
impl Shape for Rectangle {
fn area(&self) -> i32 {
self.w * self.h
}
}
fn main() {
// YOUR CODE HERE: build a Vec<Box<dyn Shape>> containing a Square { side: 3 }
// and a Rectangle { w: 2, h: 4 }, sum their areas, and print "total area = <sum>".
todo!("build a Vec<Box<dyn Shape>> and print the total area");
}