On first look, this looks relatively sane. Feel free to elaborate what aspects of this code you feel have the potential of being considered โabuseโ
Also, running cargo clippy will correctly point out a useless call to .into() (unnecessarily converting to the same type it already was) as well as a useless call to .to_string() (unnecessarily turning a type that implements Display into a String before passing result to println!) in this code, but thatโs unrelated to the main question.
Just a small nit, but I would probably try get rid of SearchIterationResult by putting the finished field into SearchResult itself and return that from next. I don't know your context and this may not be feasible/desired for your real problem, so feel free to ignore this
Thank you both for your quick replies @H2CO3@steffahn. I wasn't sure if a mutable reference to the "collection" is considered acceptable if I don't intend to obtain a mutable reference to the collection's items like with an iter_mut on a Vec.
@steffahn Thanks for pointing out clippy. Haven't come across that.
What I'd like to achieve basically is, to collect some metrics during the iteration (and print them to stdout or similar) and access the final search result after the iteration from Search. Does that make sense?
Then I'd probably change your interface a little so I'd have all the functionality (result + meta information gathering) in a single place, namely step. Or if you have a lot of metadata, a dedicated private method on Search rather than doing it directly in Iterator::next. I find this design to be conceptually easier to follow than having to look across implementation blocks, but again, this is opinionated and only a nitpick:
...
fn step(&mut self) -> SearchIterationResult {
// doing some calculations here
thread::sleep(time::Duration::from_millis(1500));
self.current_result = SearchResult {
// store this iterations' result
result: self.current_result.result + 1,
};
SearchIterationResult {
finished: Utc::now(),
current_result: self.current_result.clone(),
}
}
}
struct SearchIterator<'a> {
search: &'a mut Search,
}
impl<'a> Iterator for SearchIterator<'a> {
type Item = SearchIterationResult;
fn next(&mut self) -> Option<Self::Item> {
Some(self.search.step())
}
}
Why are Search and SearchIterator two separate types? The way I see it here it would probably make sense to just make it one struct. You kind of have the iteration state spread between two instances.
|
69 | for result in search.iter().take(5) {
| ------------- mutable borrow occurs here
...
80 | search.current_result.result
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
|