We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership I: Moves, Copy, Clone, Drop step 4 of 20
Reading E0382 line by line
Repair stage_a, stage_b and stage_c so the supplied run function
returns three groups of strings. Keep the driver and the four helpers
(tag, width, absorb and loud) unchanged, and use those helpers in
the corresponding stages.
pub fn run(inputs: Vec<String>) -> Vec<String>
For inputs = ["Ada", "Bob"], return:
["[Ada]:3", "[Bob]:3", "0=Ada", "1=Bob", "ADA/Ada", "-/Bob"]
The groups appear in this order:
| Stage | Output for each input |
|---|---|
| A | The text in square brackets, then : and its Unicode scalar value count. |
| B | Its zero-based position, then = and the original text. |
| C | Uppercase text at even indices, or - at odd indices, then / and the original text. |
Each group preserves input order. Empty input returns an empty vector.
width uses chars().count(): it counts Unicode scalar values, not UTF-8
bytes or visible characters. For example, "héllo" counts as five, while
"e\u{301}" counts as two. Uppercasing can change length: "straße"
becomes "STRASSE".
Reading a moved-value error
E0382 reports a use of a value after ownership has moved elsewhere.
In the starter, each stage tries to reuse a String or Vec<String> after
passing it to a function by value. These types do not implement Copy.
Look for the expression that moved the value and the later expression that needs it. The diagnostic may also explain the type involved, highlight a previous loop iteration or suggest a repair. Exact wording and suggestions depend on the code and compiler version; there is no fixed four-part format that every diagnostic must follow.
Stage A: two consuming calls
fn stage_a(word: String) -> String {
format!("{}:{}", tag(word), width(word))
}
tag takes ownership of word. The later call to width cannot consume
that same value again. With these fixed helpers, give one call a clone and
the other the original. Both receive the same text in separately owned
strings. In an API you control, a read-only helper could instead accept
&str, but changing these helpers is outside this exercise.
Stage B: keep the returned accumulator
fn stage_b(items: Vec<String>) -> Vec<String> {
let acc: Vec<String> = Vec::new();
for item in items {
absorb(acc, item);
}
acc
}
absorb takes the vector, appends one formatted item and returns the vector.
The starter discards that return value. A later iteration needs acc again,
and so does the final return. Even a single iteration would move the value
needed at the end.
Make the accumulator mutable and assign the result back on each iteration:
acc = absorb(acc, item);
This initializes the binding again after its old value moves into the call.
A moved binding can receive a new value; it cannot be read while uninitialized.
absorb(acc.clone(), item) without retaining the result would compile, but
the original accumulator would stay empty. Cloning and retaining the result
could produce correct output, but copying the growing vector is unnecessary.
Stage C: a move on one branch
fn stage_c(word: String, shout: bool) -> String {
let head = if shout { loud(word) } else { String::from("-") };
format!("{head}/{word}")
}
When shout is true, loud consumes word. The final formatting expression
still needs to borrow its original text. Giving loud a clone preserves
that text; the false branch needs no clone.
Check behavior after fixing ownership
A compiler suggestion can resolve an ownership error without producing the output you intended. Check all three groups, including empty strings and Unicode text, then address Clippy warnings. Passing this exercise requires compilation, correct results and the lint gate.
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.