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
Two tiny functions. The whole exercise is the difference between their return types.
pub fn first_word(s: &str) -> &str // borrows: a slice OF the input
pub fn shout(s: &str) -> String // owns: brand-new data
first_word returns everything before the first ASCII space, or the whole
string if there is no space. shout returns s uppercased with one !
appended.
Why these two, together
Every function that takes a &str and produces text has to answer one
question before anything else: is my output a view into my input, or is it
new data?
-
first_word("hello world")is"hello"— those five bytes are already in the caller’s string. Copying them would be waste. Return a&strthat points at the caller’s bytes. -
shout("hello world")is"HELLO WORLD!"— those bytes do not exist anywhere yet. Uppercasing can change byte length (ß→SS), and the!is invented. There is nothing to point at, so the function must allocate and hand back aString.
Get this fork wrong in the borrowing direction and you meet E0515: cannot return value referencing local variable. That is exactly what the starter does, on purpose. Read the error before you touch anything:
let owned = s.to_string(); // a fresh String that lives inside this call
&owned[..i] // a slice of it...
…and the function returns. owned is dropped at the closing brace, so the
slice you handed back would point at freed memory. The compiler is not being
fussy; it caught a use-after-free at compile time. No annotation can fix
this — the caller decides how long the returned reference must be valid, and
a local cannot satisfy a promise made to the caller. The fix is to slice the
input, which the caller already owns and which outlives the call.
The pins
The last two lines of the file are signature pins:
const _: for<'a> fn(&'a str) -> &'a str = first_word;
const _: fn(&str) -> String = shout;
Each one coerces your function into a function-pointer type. If your signature
does not match — say you “fixed” first_word by returning String — the
coercion fails to compile. Do not edit or delete them; a submission without
them is a failed submission. They are how this problem grades a decision that
no runtime assertion could ever see.
Edges the tests check
-
""→first_wordis"",shoutis"!". -
" lead"(leading space) →first_wordis"", not"lead". The first space is at index 0. -
"trailing "→"trailing". -
Multibyte input must survive.
find(' ')returns a byte index, and slicing astrat a non-character boundary panics — here you are slicing at the position of an ASCII space, which is always a valid boundary, so you are safe. It is worth knowing why you are safe rather than assuming it.
A note on tactics: s.split(' ').next().unwrap() looks tempting. unwrap is
not linted by default here, but reaching for it whenever you are “pretty sure”
is how panics get shipped. find + match, or unwrap_or, says what you
mean without the gamble.
Loading visualization…
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.