If you are studying iterators, I suggest that you first decide what you want to do before you do it.
For example, here is an example with one memory allocation:
fn reverse_string(input: &str) -> String { let mut result = String::with_capacity(input.len()); for portion in input.split('/') { if !result.is_empty() { result.push('/'); } for c in portion.chars().rev() { result.push(c); } } result }
Iterators usually focus on clean methods that do not change the environment. Unfortunately, this can lead to inefficiencies here, since it involves creating and deleting a String left and right.
Now, technically you can change the environment in map ( FnMut is required), it just frowned because the participating readers expect it to be clean.
As a result, when you want to add additional state, Iterator::fold is the go-to method:
fn reverse_string(input: &str) -> String { input .split('/') .fold( String::with_capacity(input.len()), |mut acc, portion| { if !acc.is_empty() { acc.push('/'); } for c in portion.chars().rev() { acc.push(c); } acc } ) }
The first argument is the drive that is passed to each close call, which then returns it. Finally, at the end of the call to fold , the battery is returned.
This is equivalent to the first function, both in terms of logic and efficiency, but honestly, here I prefer the for version to be honest.
source share