We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Generics and Traits step 1 of 24
Traits as shared behaviour
A trait names a set of methods that different types can promise to
provide. Generic functions use traits as bounds (fn f<T: Shape>(t: &T)),
trait objects such as Box<dyn Shape> call trait methods on values whose
concrete type is chosen at run time, and much of the standard library's shared
behaviour is written as traits: Display for formatting, Iterator for
iteration, PartialEq for ==, From for conversions and Add for +.
Here is the trait this exercise uses:
pub trait Shape {
fn area(&self) -> f64;
}
It declares one required method. Any type that implements Shape must
provide area, which borrows the value (&self) and returns an f64. The
trait has no fields and gives area no default body, so it states what can be
asked of a shape but not how to compute it. Each type keeps its own fields and
implements the trait in a separate block:
pub struct Circle {
pub radius: f64,
}
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
The impl Shape for Circle block is written outside the struct Circle
definition. Because a type and its trait implementations are separate items,
you can implement your own trait for a type defined elsewhere, such as f64,
and you can implement a standard trait such as Display for your own type.
The orphan rule forbids most of the remaining combination: implementing a
trait from another crate for a type from another crate, for example
impl std::fmt::Display for Vec<i32>, is rejected with E0117. (The rule has
narrow exceptions when one of your own types appears in the implementation,
as in impl From<Circle> for String.)
Your task
pub fn areas(specs: Vec<(String, Vec<f64>)>) -> Vec<f64>
specs is a list of (tag, parameters) pairs. Return one area per pair, in
the same order as the input. An empty input gives an empty output.
("circle", [r]), with exactly one parameter: areaπ · r · r.("rect", [w, h]), with exactly two parameters: areaw · h.- Anything else contributes
0.0. That includes an unknown tag such as"triangle", a tag that differs in case or spacing ("Circle"," rect"), and a known tag with the wrong number of parameters, such as("rect", [3.0])or("circle", [2.0, 9.0]).
Tags are compared exactly. Parameters are finite numbers and are not validated: a negative radius still gives a non-negative area because it is squared, and a rectangle with one negative side gives a negative area. Return the computed values without rounding them; the grader compares numbers with a small tolerance.
The starter and its first error
The starter defines the trait, both structs and a complete areas function.
For each pair, areas builds a Box<dyn Shape> (a heap-allocated value used
only through the Shape trait), uses None when the pair matches neither
shape, and calls area on the result. What is missing is the two method
bodies: impl Shape for Circle {} and impl Shape for Rect {} are empty.
Compile before changing anything. rustc reports this error once for each
empty block:
error[E0046]: not all trait items implemented, missing: `area`
E0046 lists the required items that an impl block has not provided yet, so
you can read it as a checklist. Add an area method to each block.
Two more errors are worth causing on purpose.
- Misspell the method as
fn are(&self) -> f64inside one of the impl blocks. rustc reports E0407, "methodareis not a member of traitShape", and also E0046 for theareathat is still missing. When both appear for the same block, a misspelled method name is a likely cause. - Call
perimeter()on aCircle. rustc reports E0599, no method namedperimeterfound for structCircle. ImplementingShapegivesCircleonly the methods thatShapedeclares, and nothing here declaresperimeter.
Why the entry point takes tags and numbers
Each test case is stored as JSON, and a fixed harness converts it into Rust
values before calling areas. The harness can build strings, numbers and
vectors, but it does not know about Circle, Rect or Shape. So the entry
point takes plain data, a String naming the shape plus a Vec<f64> of its
parameters, and your code builds the shapes inside the function and returns
plain f64 values.
To pass, the code must compile, return the expected areas and produce no
warnings under cargo clippy -- -D warnings.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.