Skip to content

← Ground Rules: Values, Types, Control Flow step 14 of 24

Easy Primitives

Build FizzBuzz strings with an if expression

Return one string for each integer from 1 through n, in ascending order.

pub fn fizzbuzz_codes(n: u32) -> Vec<String>
Number String
Multiple of both 3 and 5 "FizzBuzz"
Multiple of 3 only "Fizz"
Multiple of 5 only "Buzz"
Neither The number in decimal, with no extra spaces

For n = 5, return ["1", "2", "Fizz", "4", "Buzz"]. For n = 15, the last entry is "FizzBuzz". The vector has exactly n entries; n = 0 returns an empty vector, and n = 1 returns ["1"].

Use the supplied loop and one if/else if/else expression to compute each string. Bind its result to code, then push once after the branches. Do not return early or push from individual branches. Inputs are small enough for the resulting vector and strings to fit in memory.

Fix the incompatible branch types

The starter's first three branches produce string literals of type &str. The final branch calls i.to_string(), which produces an owned String. Those branches do not form a compatible result type here, so compilation fails with E0308.

Make each branch produce a String, as required by Vec<String>. Keep the multiple-of-15 case first: an else if chain selects its first true condition, and a multiple of 15 is also a multiple of 3 and of 5.

An if expression produces a value

Rust uses if expressions where other languages might use a conditional operator. This complete example binds the selected branch value:

fn main() {
    for (n, expected) in [(4, "positive"), (0, "non-positive"), (-4, "non-positive")] {
        let text = if n > 0 {
            "positive".to_string()
        } else {
            "non-positive".to_string()
        };
        assert_eq!(text, expected);
    }
}

A branch's final expression supplies its value. Adding a semicolon after that expression turns it into a statement, so an otherwise empty end of the block produces () instead. The semicolon after the entire let binding is different: it ends the declaration.

The branches must have compatible types. They can sometimes coerce to a common type, and a branch that diverges, such as an early return, is a special case. For this task, producing String in every branch is the direct solution.

An if without else has the unit type (), so it cannot provide a fallback integer or string. For ordinary conditional expressions, the condition must be bool: Rust does not treat a nonzero integer as true. Pattern conditions such as if let use separate syntax.

Test divisibility directly

The starter already uses i.is_multiple_of(15), i.is_multiple_of(3) and i.is_multiple_of(5). Keep these calls: each directly expresses the divisibility check needed by its branch.

The divisors here are fixed nonzero values. More generally, unsigned is_multiple_of(0) returns true only when its receiver is zero; a remainder operation with zero as its divisor panics. That distinction does not change this exercise, which starts at 1.

The inclusive range 1..=n visits the endpoint. When n is zero, its start exceeds its end, so it yields no values.

Your solution must compile, preserve the required control-flow structure, match the outputs and pass Clippy with warnings treated as errors.