We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Errors Are Values step 11 of 24
Propagating with ?
Refactor pipeline(input: String) -> Result<i32, String> to propagate
errors with ?. Keep the four supplied helpers unchanged.
Required behavior
Trim whitespace from both ends of the original input once. Then run these steps in order, stopping at the first failure and returning its exact message:
| Step | Success | Failure message |
|---|---|---|
non_empty |
The trimmed text is nonempty | empty input |
strip_tag |
Remove the exact lowercase prefix n= |
missing `n=` prefix in `TEXT` |
to_number |
Parse the remaining text as an i32 |
not a number: TEXT |
in_range |
The number is between 1 and 1000, inclusive | out of range: NUMBER |
Here TEXT is the text that reached that helper, and NUMBER is the
parsed integer. Preserve the messages, including their spaces and backticks.
For example, " n=42 " returns Ok(42), "42" returns
Err("missing `n=` prefix in `42`"), and "n=5000" returns
Err("out of range: 5000").
Do not trim again after removing the prefix. "n= 42" fails parsing with
"not a number: 42", which has two spaces after the colon.
"n=" produces "not a number: ", including the trailing space.
Parsing accepts a leading + or - and leading zeroes, but not decimal
points, underscores or non-ASCII digits. Thus "n=+0042" succeeds,
"n=-1" reaches the range check, and "n=2147483648" fails parsing
because it exceeds i32::MAX.
Replace the propagation matches
The starter computes the right results, but Clippy rejects its redundant
matches when warnings are denied. The first three matches trigger
question_mark: each extracts an Ok value or immediately returns
the error.
For a Result, expr? produces the value inside Ok. On Err,
it returns early from the enclosing function or closure, converting the
error through From when needed. Here every helper and pipeline
uses String, so propagation preserves the error without reformatting it.
Replace those three matches with ?. The last match merely rebuilds
the same Result and triggers needless_match; return in_range(n)
directly. Three bindings followed by that final expression make a clear
four-line body. The tests do not count source lines.
Writing Ok(in_range(n)?) also works at runtime, but triggers
needless_question_mark here because the inner result already has the
function's return type. In other code, an error conversion or additional
success-path work can make ? necessary.
Where an early return goes
An ordinary block does not create a new return boundary. A closure does. This complete example parses each input independently, so a failure does not stop the surrounding iteration:
fn main() {
let results: Vec<Result<i32, std::num::ParseIntError>> =
["2", "bad", "4"]
.into_iter()
.map(|text| {
let n = text.parse::<i32>()?;
Ok(n * 2)
})
.collect();
assert_eq!(results[0], Ok(4));
assert!(results[1].is_err());
assert_eq!(results[2], Ok(8));
}
Use match when you need to recover differently for particular failures,
or map_err to transform an error before propagating it. Do neither in
this exercise: its contract requires the helper messages unchanged.
Choosing error types
String keeps this exercise focused on propagation. It can contain
descriptive information and its text can be inspected, but callers would
have to compare or parse messages to distinguish error categories.
A dedicated error enum gives those categories explicit variants and fields.
The lessons on implementing the Error trait and From conversions develop that approach.
The submission must compile, pass the output cases and pass Clippy with warnings denied.
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.