I often see the pattern where I need to loop over a range and call a function that takes ownership of its argument. Since that function takes ownership of its argument, I must clone the value. For example:
let a = "hello".to_string();
for i in 0..10 {
print_me(a.clone());
}
fn print_me(s: String) {
println!("{}", s);
}
I would like to find a pattern where the value is cloned for all calls except the last one as to prevent a redundant clone.
The simplest approach is to add an explicit check on the loop index:
for i in 0..10 {
if i == 9 {
print_me(a);
} else {
print_me(a.clone());
}
}
But the compiler is not able understand the pattern and complains about the moved value during iteration.
I also tried to build an iterator that does the clones and move using repeat_with()
, chain()
and once()
but the closure cosumes the value:
let iter = std::iter::repeat_with(|| a.clone())
.take(9)
.chain(std::iter::once(a))
What would be the easiest way to achieve this pattern?
Thanks!
As an alternative solution, you can make the compiler understand that it is in fact the last iteration by breaking out of the loop:
for i in 0..10 {
if i == 9 {
print_me(a);
break;
} else {
print_me(a.clone());
}
}
itertools::repeat_n
does exactly this:
#[derive(Clone, Debug)]
pub struct RepeatN<A> {
elt: Option<A>,
n: usize,
}
/// Create an iterator that produces `n` repetitions of `element`.
pub fn repeat_n<A: Clone>(element: A, n: usize) -> RepeatN<A> {
if n == 0 {
RepeatN { elt: None, n, }
} else {
RepeatN { elt: Some(element), n, }
}
}
impl<A: Clone> Iterator for RepeatN<A> {
type Item = A;
fn next(&mut self) -> Option<Self::Item> {
if self.n > 1 {
self.n -= 1;
self.elt.as_ref().cloned()
} else {
self.n = 0;
self.elt.take()
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.n, Some(self.n))
}
}
Using unsafe
code you could make a (slightly) more efficient implementation however.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With