Rust 带回调的类'zip'函数中的借用检查器问题
我试图实现一个函数,该函数同时遍历两个迭代器,为每对迭代器调用一个函数。这个回调可以通过返回Rust 带回调的类'zip'函数中的借用检查器问题,rust,borrow-checker,Rust,Borrow Checker,我试图实现一个函数,该函数同时遍历两个迭代器,为每对迭代器调用一个函数。这个回调可以通过返回(bool,bool)元组来控制在每个步骤中哪些迭代器是高级的。由于迭代器在我的用例中引用了缓冲区,因此它们不能实现stdlib中的迭代器特性,而是通过next\u ref函数使用,该函数与Iterator::next相同,但需要一个额外的生存期参数 // An iterator-like type, that returns references to itself // in next_ref str
(bool,bool)
元组来控制在每个步骤中哪些迭代器是高级的。由于迭代器在我的用例中引用了缓冲区,因此它们不能实现stdlib中的迭代器
特性,而是通过next\u ref
函数使用,该函数与Iterator::next
相同,但需要一个额外的生存期参数
// An iterator-like type, that returns references to itself
// 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 over two RefIter simultaneously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(mut iter1: RefIter, mut iter2: RefIter, callback: F)
where 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)
});
}
我理解它为什么抱怨,但找不到解决办法。我非常感谢在这个问题上的任何帮助
链接到。中的此代码片段此代码的问题在于,
RefIter
以两种方式使用,这两种方式基本上是相互矛盾的:
的调用者收到对存储值的引用,该值与next\u ref
RefIter
的值需要是可变的,以便在每次调用时可以递增RefIter
都能工作,您需要修改RefIter
,以避免传递对您希望变异的数据的引用。
我使用RefCell
和Rc
的组合实现了以下一种可能性:
use std::cell::RefCell;
use std::rc::Rc;
// An iterator-like type, that returns references to itself
// in next_ref
struct RefIter {
value: RefCell<Rc<u64>>
}
impl RefIter {
fn next_ref(&self) -> Option<Rc<u64>> {
let new_val = Rc::new(**self.value.borrow() + 1);
*self.value.borrow_mut() = new_val;
Some(Rc::clone(&*self.value.borrow()))
}
}
// Iterate over two RefIter simultaniously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(iter1: RefIter, iter2: RefIter, callback: F)
where F: Fn(&Option<Rc<u64>>, &Option<Rc<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 iter1 = RefIter { value: RefCell::new(Rc::new(3)) };
let iter2 = RefIter { value: RefCell::new(Rc::new(4)) };
each_zipped(iter1, iter2, |val1, val2| {
// We can't use unwrap() directly, since we're only passed a reference to an Option
let val1 = **val1.iter().next().unwrap();
let val2 = **val2.iter().next().unwrap();
println!("{}, {}", val1, val2);
(val1 < 10, val2 < 10)
});
}
使用std::cell::RefCell;
使用std::rc::rc;
//一种类似迭代器的类型,返回对自身的引用
//在下一个参考中
结构改装机{
值:RefCell
}
impl改装机{
fn next_ref(&self)->选项{
让new_val=Rc::new(**self.value.borrow()+1);
*self.value.borrow_mut()=new_val;
一些(Rc::clone(&*self.value.borrow())
}
}
//同时迭代两个重新安装程序并调用回调
//每一双。回调函数返回一个布尔元组
//指示哪些迭代器应该是高级的。
fn每个拉链(iter1:改装器,iter2:改装器,回拨:F)
其中F:Fn(&Option,&Option)->(bool,bool)
{
让mut current1=iter1.next_ref();
让mut current2=iter2.next_ref();
环路{
让前进标志=回调(¤t1和¤t2);
预赛{
(对,对)=>{
current1=iter1.next_ref();
current2=iter2.next_ref();
},
(对、错)=>{
current1=iter1.next_ref();
},
(假、真)=>{
current2=iter1.next_ref();
},
(假,假)=>{
返回
}
}
}
}
fn main(){
设iter1=RefIter{value:RefCell::new(Rc::new(3))};
设iter2=RefIter{value:RefCell::new(Rc::new(4))};
每个拉链(iter1、iter2、val1、val2){
//我们不能直接使用unwrap(),因为我们只传递了对选项的引用
设val1=**val1.iter().next().unwrap();
设val2=**val2.iter().next().unwrap();
println!(“{},{}”,val1,val2);
(val1<10,val2<10)
});
}
此版本的RefIter
将Rc
s分发给消费者,而不是参考资料。这避免了可变别名的问题-通过放置
将新的Rc
插入外部RefCell
。这样做的一个副作用是,消费者能够保留对缓冲区的“旧”引用(通过返回的Rc
),即使在RefIter
升级之后也是如此
由于迭代器在我的用例中引用了缓冲区,因此它们不能实现stdlib中的迭代器
特性,而是通过next\u ref
函数使用,该函数与Iterator::next
相同,但需要一个额外的生存期参数
// An iterator-like type, that returns references to itself
// 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 over two RefIter simultaneously and call a callback
// for each pair. The callback returns a tuple of bools
// that indicate which iterators should be advanced.
fn each_zipped<F>(mut iter1: RefIter, mut iter2: RefIter, callback: F)
where 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)
});
}
您正在描述一个流迭代器。这有一个板条箱,恰如其分地叫做。文档描述了您的问题(重点是我的):
而标准的迭代器trait的功能是基于
next
方法,StreamingIterator
的功能基于
一对方法:advance
和get
。这从本质上分裂了
next
一半的逻辑(实际上,StreamingIterator
的next
方法
只调用advance
,然后调用get
)
这是必需的,因为Rust对借词的词法处理(更多
特别是缺少单笔进入、多笔退出借款)如果
StreamingIterator
的定义类似于Iterator
,只需要一个
next
方法,无法定义像filter
这样的操作。
板条箱当前没有zip
功能,当然也不是您描述的变体。但是,它很容易实现:
extern crate streaming_iterator;
use streaming_iterator::StreamingIterator;
fn each_zipped<A, B, F>(mut iter1: A, mut iter2: B, callback: F)
where
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 for 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)
});
}
extern板条箱流式迭代器;
使用streaming_iterator::StreamingIterator;
fn每个压缩(mut iter1:A、mut iter2:B、回调:F)
哪里
A:StreamingIterator,
B:StreamingIterator,
F:例如,我认为你认为改装机本身的设计有缺陷是不对的。我们可以轻松地一次遍历一个迭代器:。当使用Rc
时,我也可以使用普通的迭代器,但在我的用例中,我希望返回对同一缓冲区不同部分的引用(在读取新数据时也会发生变化)。问题似乎更多地与非词汇生存期有关。在每个压缩的的开头,我们对current1
进行可变引用。然后,我们使用该值调用回调。在这一点上,我们不再需要参考。我们可以随时打电话给你