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(¤t1, ¤t2); 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 thoughnext_ref
function, identicaliterator::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 ofnext
method,streamingiterator
's functionality based off of pair of methods:advance
,get
. splits logic ofnext
in half (in fact,streamingiterator
'snext
method nothing calladvance
followedget
).this required because of rust's lexical handling of borrows (more lack of single entry, multiple exit borrows). if
streamingiterator
definediterator
requirednext
method, operationsfilter
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
Post a Comment