We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership III: Lifetimes, Explicitly step 3 of 22
Borrow it or own it: your first lifetime decision
Implement two functions that return text in different ways:
pub fn first_word(s: &str) -> &str
pub fn shout(s: &str) -> String
first_word returns a slice of the input before its first ASCII space
(' '). If there is no space, return the whole input. Do not trim the input:
a leading space gives an empty result. Tabs, newlines and other Unicode
whitespace are ordinary characters for this function.
shout returns an owned string containing the Unicode uppercase conversion
of the entire input, followed by one additional !. Keep whitespace and
existing punctuation. Use the conversion provided by str::to_uppercase.
| Input | first_word |
shout |
|---|---|---|
"hello world" |
"hello" |
"HELLO WORLD!" |
"" |
"" |
"!" |
" lead" |
"" |
" LEAD!" |
"trailing " |
"trailing" |
"TRAILING !" |
"straße!" |
"straße!" |
"STRASSE!!" |
Borrow a view, own a transformed result
For first_word, the desired bytes already form a prefix of s. Return
that prefix without making a separate string. The result borrows the input
and cannot be used after the borrowed data becomes invalid.
For shout, the return type is String, so the caller owns the result
independently of the input. to_uppercase() returns a String; append the
exclamation mark to it. Unicode conversion can expand one character into
several, as with ß becoming SS. Do not assume one output character per
input character or restrict the conversion to ASCII.
Why the starter fails
The starter copies s into a local String named owned, then tries to
return a slice of that local string. Rust rejects this with E0515. owned
would be dropped when the function returned, leaving the result pointing
into storage that no longer belongs to a live string.
Return a slice of s instead. Lifetime annotations cannot extend the life
of the local allocation. The signature already uses lifetime elision: with
one input reference lifetime, the output reference receives that lifetime.
The relationship is equivalent to fn first_word<'a>(s: &'a str) -> &'a str.
You do not need to write the annotation to express it. See the
lifetime-elision rules.
Keep the signature checks
The starter includes these compile-time checks:
const _: for<'a> fn(&'a str) -> &'a str = first_word;
const _: fn(&str) -> String = shout;
Each assignment checks that the function can be used with the stated
function-pointer type. Returning String from first_word would fail the
first check. Keep these declarations and the required function signatures. The grader
also checks these function-pointer types independently of the starter.
These checks describe compatible types and lifetimes. They do not establish
which allocation a returned reference points into, or whether a function
allocates internally. The exercise still requires first_word to return a
slice of its input.
Find a safe slice boundary
s.find(' ') returns an optional byte index. If a space is found, its start
is a UTF-8 character boundary, so &s[..index] is a valid slice. If no space
is found, use s itself. Counting characters and using that count directly as
a byte index would not work for arbitrary UTF-8 input.
Splitting on the literal space is another valid approach. In particular,
s.split(' ').next() has a first item even when s is empty, so an unwrap
on that specific result does not introduce an empty-input panic. That
guarantee does not extend to every iterator. split_whitespace() has
different behavior and would change this task's leading-space and delimiter
rules. The str documentation
describes these methods.
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.