错误:闭包要求对“ self”具有唯一的访问权,但“ self”已被借用

max*_*lun 5 rust

我正在学习Rust,并决定实现一个计件表(在本pdf的 6.4节中进行了介绍),因为它非常简单,但并不简单。

这通常是非常简单的,但是我遇到了一个我真的无法弄清楚的问题。这是我的代码的简化版本,以供参考:

use std::ops::Index;

#[derive(Debug)]
pub struct PieceTable {
    // original file data: never changes
    orig_buffer: Vec<u8>,
    // all new data is pushed onto this buffer
    add_buffer: Vec<u8>,
    // the pieces that currently make up the file
    pieces: Vec<Piece>,
}

#[derive(Debug, Copy, Clone)]
enum Location {
    Orig,
    Add,
}

#[derive(Debug, Copy, Clone)]
struct Piece {
    // which buffer is this piece located at?
    buf: Location,
    // starting offset
    start: usize,
    // size of piece
    length: usize,
}

impl PieceTable {
    pub fn iter(&self) -> PieceTableIterator {
        PieceTableIterator::new(self)
    }

    fn piece_buf(&self, piece: &Piece) -> &Vec<u8> {
        match piece.buf {
            Location::Orig => &self.orig_buffer,
            Location::Add => &self.add_buffer,
        }
    }

    fn piece_value(&self, piece: &Piece, index: usize) -> &u8 {
        &self.piece_buf(piece)[index]
    }
}

pub struct PieceTableIterator<'a> {
    table: &'a PieceTable,
    buf_iter: Option<std::slice::Iter<'a, u8>>,
    piece_iter: std::slice::Iter<'a, Piece>,
}

impl<'a> PieceTableIterator<'a> {
    fn new(table: &PieceTable) -> PieceTableIterator {
        let mut iter = table.pieces.iter();
        let piece = iter.next();
        let buf_iter = piece.map(|p| table.piece_buf(p).iter());
        PieceTableIterator {
            table: table,
            buf_iter: buf_iter,
            piece_iter: iter,
        }
    }
}

impl<'a> Iterator for PieceTableIterator<'a> {
    type Item = u8;

    fn next(&mut self) -> Option<u8> {
        if self.buf_iter.is_none() {

            return None;
        }
        match self.buf_iter {
            Some(ref mut iter) => {
                iter.next()
                    .or_else(|| {
                        self.piece_iter.next().and_then(|p| {
                            let mut buf = self.table.piece_buf(p)[p.start..(p.start + p.length)]
                                              .iter();
                            let item = buf.next();
                            self.buf_iter = Some(buf);
                            item
                        })
                    })
                    .map(|b| *b)
            }
            None => None,
        }
    }
}

fn main() {
    let table = PieceTable {
        orig_buffer: vec![1, 2, 3],
        add_buffer: vec![4, 5, 6],
        pieces: vec![Piece {
                         buf: Location::Orig,
                         start: 0,
                         length: 2,
                     },
                     Piece {
                         buf: Location::Add,
                         start: 0,
                         length: 3,
                     },
                     Piece {
                         buf: Location::Orig,
                         start: 2,
                         length: 1,
                     }],
    };
    // shoud print 1, 2, 4, 5, 6, 3
    for i in table.iter() {
        println!("{}", i);
    }

}
Run Code Online (Sandbox Code Playgroud)

游乐场

我正在尝试为此结构构建一个迭代器。我可以通过仅在迭代器中保留索引来非常低效地完成此操作,但是对于每个.next()调用,我都必须遍历所有片段。相反,我宁愿让我的迭代器为这些片段存储一个迭代器,为当前片段的缓冲区切片存储一个迭代器。我的问题(我尝试了几种不同的方法)是我一直遇到生命周期问题。我当前的代码给我错误:

:76:30: 84:22 error: closure requires unique access to `self` but `self.buf_iter.0` is already borrowed [E0500]
Run Code Online (Sandbox Code Playgroud)

我认为我了解,但不确定如何解决。我已经尝试了一些当前代码的变体,但它们都遇到了类似的问题。

A.B*_*.B. 5

就像错误消息告诉您一样。问题是你有重叠的可变的自我借用。

    match self.buf_iter {
        Some(ref mut iter) => { /// self.buf_iter is mutably borrowed here
            iter.next()
                .or_else(|| {
                    self.piece_iter.next().and_then(|p| { /// which is why you can't mutably borrow self here again
                        let mut buf = self.table.piece_buf(p)[p.start..(p.start + p.length)]
                                          .iter();
                        let item = buf.next();
                        self.buf_iter = Some(buf);
                        item
                    })
                })
                .map(|b| *b)
        }
        None => None,
    }
Run Code Online (Sandbox Code Playgroud)

解决方案是在第二次借贷发生之前就结束第一笔借贷。

通过编写更惯用的Rust,也可以稍微简化代码。

impl<'a> Iterator for PieceTableIterator<'a> {
    type Item = u8;

    fn next(&mut self) -> Option<u8> {
        if self.buf_iter.is_none() {
            return None;
        }

        self.buf_iter
            .as_mut()
            .and_then(Iterator::next)
            .cloned()
            .or_else(|| {
                self.piece_iter.next().and_then(|p| {
                    let mut buf = self.table.piece_buf(p)[p.start..(p.start + p.length)]
                                      .iter();
                    let item = buf.next().cloned();
                    self.buf_iter = Some(buf);
                    item
                })
            })
    }
}
Run Code Online (Sandbox Code Playgroud)