Skip to content

← Orientation and the Gate step 3 of 6

Easy Primitives

Naming conventions and the style gate

Return the sum of a slice and the number of elements in it.

pub fn summarize_scores(raw_scores: &[i32]) -> (i32, usize)

The contract

  • raw_scores may be empty. An empty slice returns (0, 0).
  • Values may be negative. The first tuple element is the arithmetic sum of every value, and the second is the slice length.
  • The tests keep every value and every total inside the i32 range, so you do not need to handle overflow. (If a sum did overflow, a debug build would panic and a release build would wrap around, unless overflow checks were configured differently.)

Examples: [10, 20, 30] returns (60, 3), and [100, -100, 0] returns (0, 3).

Why the correct starter still fails

The starter returns the right answer for every test, but it does not pass the site's Rust style check. That check runs Clippy, Rust's linter, with -D warnings. A lint is a compiler check that reports suspicious or unidiomatic code without the code being invalid. Most lints are warnings by default; -D warnings turns every warning into an error. Clippy runs the normal compiler too, so this flag denies rustc's built-in lints in addition to Clippy's extra ones.

The starter triggers five different lints and six diagnostics in total. Four of the lints come from rustc itself.

non_snake_case (reported twice, for TotalSum and Count). Rust's naming conventions are checked by warn-by-default lints. Variables and functions use snake_case. Types, traits and enum variants use UpperCamelCase (checked by non_camel_case_types). Constants and statics use SCREAMING_SNAKE_CASE (checked by non_upper_case_globals). Ordinary compilation only warns about a name like TotalSum; here the warning becomes an error. For acronyms, the convention treats the acronym as one word: HttpResponse, not HTTPResponse. Clippy's upper_case_acronyms lint enforces part of this, but by default it only reports names that are entirely uppercase, such as struct HTTP, and only on items that are not part of a public API.

unused_variables (score_limit). The variable is assigned and never read. If you deliberately want to keep an unused binding, start its name with an underscore, such as _score_limit. The compiler does not report unused bindings whose names start with _. Usually the better fix is to delete the binding.

unused_mut (result). The binding is declared mut but never changed. Removing mut tells readers that the value stays the same.

dead_code (average). A private function that nothing calls. In a larger crate this lint often finds code left behind after a refactor. In this exercise, the helper is not part of the answer, so delete it.

The fifth lint comes from Clippy.

clippy::let_and_return (let mut result = ...; result). The block stores a value in a binding only to return that binding on the next line. Return the expression directly instead: (TotalSum, Count) in place of the last two lines.

Fixing the starter

You can fix each diagnostic in place: rename the two variables, delete score_limit, return the tuple directly and delete average. A loop that accumulates the sum and count is acceptable to the gate once those changes are made.

There is also a shorter version. The slice already knows its length (.len()), and an iterator over the values can be summed with .sum(). Writing the body with those two methods leaves no accumulators, counter or temporary binding to cause lints, though average still has to be deleted.

Suppressing a lint

Sometimes a warning is intentional, for example a helper you are keeping for later. You can mark the item instead of changing the code:

  • #[allow(dead_code)] turns the lint off for that item.
  • #[expect(dead_code)] (stable since Rust 1.81) also suppresses it, but reports an unfulfilled_lint_expectations warning if the lint stops firing, for example after the function starts being called. Under -D warnings that report is also an error, so the annotation cannot stay in place after it is no longer needed.

Try deleting or fixing the code first. A suppression is for cases where the warned-about code is deliberate.

The return type

(i32, usize) is a tuple, a fixed-size group of values of possibly different types. Here it lets the function return two values without defining a struct. usize is the unsigned integer type Rust uses for lengths and indexes. Its width matches the target's pointer size: 8 bytes on 64-bit targets and 4 bytes on 32-bit targets. .len() on a slice already returns a usize, so the count needs no conversion.