rust - Borrow checker issue in `zip`-like function with a callback -


i'm trying implement function steps though 2 iterators @ same time, calling function each pair. callback can control of iterators advanced in each step returning (bool, bool) tuple. since iterators take reference buffer in use case, can't implement iterator trait stdlib, instead used though next_ref function, identical iterator::next, takes additional lifetime parameter.

// iterator-like type, returns references // in next_ref struct refiter {     value: u64 }  impl refiter {     fn next_ref<'a>(&'a mut self) -> option<&'a u64> {         self.value += 1;         some(&self.value)     } }  // iterate on 2 refiter simultaneously , call callback // each pair. callback returns tuple of bools // indicate iterators should advanced. fn each_zipped<f>(mut iter1: refiter, mut iter2: refiter, callback: f)     f: fn(&option<&u64>, &option<&u64>) -> (bool, bool) {     let mut current1 = iter1.next_ref();     let mut current2 = iter2.next_ref();     loop {         let advance_flags = callback(&current1, &current2);         match advance_flags {             (true, true) => {                 current1 = iter1.next_ref();                 current2 = iter2.next_ref();             },             (true, false) => {                 current1 = iter1.next_ref();             },             (false, true) => {                 current2 = iter1.next_ref();             },             (false, false) => {                 return             }         }     } }  fn main() {     let mut iter1 = refiter { value: 3 };     let mut iter2 = refiter { value: 4 };     each_zipped(iter1, iter2, |val1, val2| {         let val1 = *val1.unwrap();         let val2 = *val2.unwrap();         println!("{}, {}", val1, val2);         (val1 < 10, val2 < 10)     }); } 
error[e0499]: cannot borrow `iter1` mutable more once @ time   --> src/main.rs:28:28    | 22 |     let mut current1 = iter1.next_ref();    |                        ----- first mutable borrow occurs here ... 28 |                 current1 = iter1.next_ref();    |                            ^^^^^ second mutable borrow occurs here ... 42 | }    | - first borrow ends here  error[e0499]: cannot borrow `iter2` mutable more once @ time   --> src/main.rs:29:28    | 23 |     let mut current2 = iter2.next_ref();    |                        ----- first mutable borrow occurs here ... 29 |                 current2 = iter2.next_ref();    |                            ^^^^^ second mutable borrow occurs here ... 42 | }    | - first borrow ends here  error[e0499]: cannot borrow `iter1` mutable more once @ time   --> src/main.rs:32:28    | 22 |     let mut current1 = iter1.next_ref();    |                        ----- first mutable borrow occurs here ... 32 |                 current1 = iter1.next_ref();    |                            ^^^^^ second mutable borrow occurs here ... 42 | }    | - first borrow ends here  error[e0499]: cannot borrow `iter1` mutable more once @ time   --> src/main.rs:35:28    | 22 |     let mut current1 = iter1.next_ref();    |                        ----- first mutable borrow occurs here ... 35 |                 current2 = iter1.next_ref();    |                            ^^^^^ second mutable borrow occurs here ... 42 | }    | - first borrow ends here 

i understand why complains, can't find way around it. i'd appreciate on subject.

link snippet in playground.

since iterators take reference buffer in use case, can't implement iterator trait stdlib, instead used though next_ref function, identical iterator::next, takes additional lifetime parameter.

you describing streaming iterator. there crate this, aptly called streaming_iterator. documentation describes problem (emphasis mine):

while standard iterator trait's functionality based off of next method, streamingiterator's functionality based off of pair of methods: advance , get. splits logic of next in half (in fact, streamingiterator's next method nothing call advance followed get).

this required because of rust's lexical handling of borrows (more lack of single entry, multiple exit borrows). if streamingiterator defined iterator required next method, operations filter impossible define.

the crate not have zip function, , not variant have described. however, it's easy enough implement:

extern crate streaming_iterator;  use streaming_iterator::streamingiterator;  fn each_zipped<a, b, f>(mut iter1: a, mut iter2: b, callback: f)     a: streamingiterator,     b: streamingiterator,     f: for<'a> fn(option<&'a a::item>, option<&'a b::item>) -> (bool, bool), {     iter1.advance();     iter2.advance();      loop {         let advance_flags = callback(iter1.get(), iter2.get());         match advance_flags {             (true, true) => {                 iter1.advance();                 iter2.advance();             }             (true, false) => {                 iter1.advance();             }             (false, true) => {                 iter1.advance();             }             (false, false) => return,         }     } }  struct refiter {     value: u64 }  impl streamingiterator refiter {     type item = u64;      fn advance(&mut self) {         self.value += 1;     }      fn get(&self) -> option<&self::item> {         some(&self.value)     } }  fn main() {     let iter1 = refiter { value: 3 };     let iter2 = refiter { value: 4 };     each_zipped(iter1, iter2, |val1, val2| {         let val1 = *val1.unwrap();         let val2 = *val2.unwrap();         println!("{}, {}", val1, val2);         (val1 < 10, val2 < 10)     }); } 

Comments

Popular posts from this blog

node.js - Node js - Trying to send POST request, but it is not loading javascript content -

javascript - Replicate keyboard event with html button -

javascript - Web audio api 5.1 surround example not working in firefox -