An iterator method for capturing regex moves an iterator

I process simple strings of the format "1s: 1d", "100: 5000", etc. with this regex:

let retention_matcher = regex::Regex::new({r"^(\d+)([smhdy])?:(\d+)([smhdy])?$"}).unwrap(); 

I know that this regex should only match once, so I want to run regex for captures and check the number of captures.

  let iter = retention_matcher.captures_iter(ts); let count = iter.count(); println!("iter.count(): {}", count); let _ : Vec<Option<(u64,u64)>> = iter.map(|regex_match| { let retval = retention_spec_to_pair(regex_match); println!("precision_opt: {:?}", retval); retval }).collect(); 

The problem is that the count() method is moved by iter and I can no longer use it.

 src/bin/whisper.rs:147:42: 147:46 error: use of moved value: `iter` src/bin/whisper.rs:147 let _ : Vec<Option<(u64,u64)>> = iter.map(|regex_match| { ^~~~ src/bin/whisper.rs:144:21: 144:25 note: `iter` moved here because it has type `regex::re::FindCaptures<'_, '_>`, which is non-copyable src/bin/whisper.rs:144 let count = iter.count(); 

That doesn't make sense to me. Should the count method only return the copied usize value and not move iter ? How can I get around this problem?

+6
source share
1 answer

I suspect you think of iter as an abstract sequence of captures. More precisely, think of it as a position in an abstract sequence of captures. The main thing any iterator should know is to move on to the next element in the sequence; that is, you can promote the position and get the next element in the sequence.

count moves the iter , because in order to count the number of elements in a sequence, it must generate the entire sequence. This necessarily modifies the iterator, stepping over it throughout the sequence. It moves because after calling count iterator is really no longer useful. By definition, he must go past the end of the sequence!

Unfortunately, this does not look like the type of iterator in question ( FindCaptures ) Clone , so you cannot just make a copy of it.

The solution is to rebuild your code so as not to call count . If you want to get the first element and make sure that it is no longer there, the simplest template would be:

 let mut iter = ...; if let Some(regex_match) = iter.next() { // Ensure that there is no next element. assert_eq!(iter.next(), None); // process regex_match ... } 
+7
source

Source: https://habr.com/ru/post/988302/


All Articles