Skip to content

← Errors Are Values step 12 of 24

Medium Primitives

? on Option, and bridging to Result

Complete two functions that find a word on the first line of an input. One returns an Option; the other gives a descriptive error when the word is missing.

Required behavior

nth_word(s: String, n: usize) -> Option<String> returns the word at zero-based index n on the first line, as an owned String. Return None if the line or word is absent.

nth_word_len(s: String, n: usize) -> Result<usize, String> returns that word's UTF-8 byte length. If the word is absent, return the exact error format!("no word at index {n}").

Input Index Word Byte length or error
"the cat sat" 1 Some("cat") Ok(3)
"the cat sat" 9 None Err("no word at index 9")
"héllo wörld" 1 Some("wörld") Ok(6)
"alpha beta\ngamma" 2 None Err("no word at index 2")

The displayed words are shorthand for owned Strings. The harness writes None as JSON null; on failure it also writes a null length and the error message.

Define the first line before splitting words

Use str::lines to find the first line. It recognizes newline (\n) and carriage-return/newline (\r\n) endings and excludes those terminators from the returned text.

An empty string has no first line. A string starting with \n has an empty first line, so "\nsecond line" still has no word at index zero. Do not skip an empty or whitespace-only first line to search later lines.

Then use split_whitespace, which recognizes Unicode whitespace and never yields empty words. A lone \r is whitespace but is not a line ending for lines: "one\rtwo" has two words on its first line. Punctuation remains part of a word.

The returned length counts bytes, not Unicode scalar values or visible characters. For example, "wörld" occupies six UTF-8 bytes.

Propagate absence inside Option

s.lines().next() returns Option<&str>. Applying ? extracts the line or returns None from nth_word. The word lookup returns another Option and can use ? in the same way.

Convert the selected slice into an owned String before returning it. Returning a slice into the consumed input would leave it referring to storage that the function drops.

Supply an error when returning Result

The starter applies ? directly to nth_word(s, n) inside a function returning Result. That fails with E0277: an absent Option contains no error value for the function to return.

Convert it first:

let word = nth_word(s, n)
    .ok_or_else(|| format!("no word at index {n}"))?;

This fragment belongs inside nth_word_len. On success, ok_or_else produces Ok(word), and ? extracts the String so you can return its length. On absence, the closure creates the message and ? returns that error immediately.

ok_or can express the same conversion, but its argument is evaluated eagerly. Here ok_or(format!(...)) would format a message even when the word exists. Use ok_or_else to defer that work.

Going from Result to Option is a different choice: .ok() discards an error and turns it into None. Use that direction only when losing the error details is intended.

Why unwrap does not meet the contract

An unchecked unwrap or expect would panic when the word is missing. This function must return an error instead. The supplied source explicitly denies Clippy's unwrap_used and expect_used lints, so those calls also fail the lint check. Those lints are not enabled by default in Clippy.

? depends on both the operand and the return type of the enclosing function or closure. Here the Option lookups belong in nth_word, and the converted Result belongs in nth_word_len. For more detail, see how the operator propagates failure.

The submission must compile, match the output cases and pass Clippy with warnings denied.