We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Closures and Iterators step 7 of 28
Filter borrowed values into owned results
Repair the iterator chains so they filter borrowed inputs into owned results. Keep the supplied signature:
pub fn evens_then_names(nums: &[i64], names: &[String]) -> (Vec<i64>, Vec<String>)
The first output contains every even number from nums, including zero and negative even numbers. Inputs may use the full i64 range. The second output contains every name with at least four UTF-8 bytes, preserving its exact text. Keep input order and duplicates in both outputs. Either input can be empty; its corresponding output is then empty. Do not change the caller's data.
For [1, 2, 3, 4] and ["ab", "abcd", "xyz"], return
([2, 4], ["abcd"]). Length means bytes, not characters or graphemes:
"é" has two bytes, "éé" has four, and "🦀" also has four.
Whitespace and control characters count toward byte length too.
Track the item type through the chain
nums.iter() yields &i64. The filter predicate receives a reference to
each item, so its parameter is &&i64. Filtering decides whether to yield
the original item; it does not change that item's type.
| Expression | Iterator item | Filter predicate receives |
|---|---|---|
nums.iter().filter(...) |
&i64 |
&&i64 |
nums.iter().copied().filter(...) |
i64 |
&i64 |
names.iter().filter(...) |
&String |
&&String |
The starter has two separate problems. Its numeric predicate uses % on
&&i64, for which the needed remainder implementation is unavailable.
Also, both chains still yield references, while the requested vectors own
i64 and String values. Fixing only the predicate leaves the collection errors.
Method calls such as s.len() can automatically dereference the String
references. Do not assume that an operator expression follows the same
method-lookup rules. For this numeric predicate, dereferencing or a reference
pattern makes the intended integer operation explicit.
Copy integers out of the borrowed sequence
This complete example shows three equivalent ways to collect integers:
fn main() {
let nums = [-2_i64, -1, 0, 1, 2];
let a: Vec<i64> = nums.iter().filter(|&&n| n % 2 == 0).copied().collect();
let b: Vec<i64> = nums.iter().filter(|n| **n % 2 == 0).copied().collect();
let c: Vec<i64> = nums.iter().copied().filter(|n| n % 2 == 0).collect();
assert_eq!(a, [-2, 0, 2]);
assert_eq!(a, b);
assert_eq!(b, c);
assert_eq!(nums, [-2, -1, 0, 1, 2]);
}
In the first two chains, filter still yields &i64; copied converts the
survivors to i64. In the third, copied changes the item before filtering.
The predicate still receives a reference, now &i64, which supports this
remainder expression. copied removes one reference layer, not every layer
that a later adapter might introduce.
Clone only the strings you keep
String is not Copy. Moving a String out through a shared reference is not allowed, so use cloned to obtain owned copies of the selected strings. Filtering first avoids cloning rejected names:
fn main() {
let names = [String::from("hi"), String::from("🦀"), String::from("hello")];
let kept: Vec<String> = names.iter().filter(|s| s.len() >= 4).cloned().collect();
assert_eq!(kept, ["🦀", "hello"]);
assert_eq!(names, ["hi", "🦀", "hello"]);
}
On an iterator of &T, cloned calls T's Clone implementation. Here T is
String. On an iterator of &&String, cloning one layer would instead clone
a reference; it would not produce an owned String.
Both copied and cloned work for i64, but copied states that no Clone call is needed. Clone is a trait operation and can have type-specific behavior. See the iterator adapter documentation.
Keep the borrowing API and pass Clippy
The slice references are already passed by value; their elements remain borrowed. Accepting owned Vec inputs would be a different API and is not part of this repair.
Clippy flags explicit copying or cloning map closures with map_clone,
such as .map(|n| *n) over &i64 or .map(|s| s.clone()) over &String.
Use the dedicated adapters. On the String chain, iter_overeager_cloned
flags cloning before this filter. The work saved depends on which inputs
fail the predicate, not on an assumed rejection rate.
Passing requires the expected results, compilation and Clippy with warnings treated as errors.
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.