错误:关闭需要对“self”的唯一访问权限,但“self”已经被借用了

时间:2016-03-11 19:31:03

标签: rust

我正在学习Rust,并决定实现一个表格(在this 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);
    }

}

Playground

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

:76:30: 84:22 error: closure requires unique access to `self` but `self.buf_iter.0` is already borrowed [E0500]

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

2 个答案:

答案 0 :(得分:4)

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

    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,
    }

解决方案是在第二个借位结束之前进行第一次借用。

通过编写更多惯用的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
                })
            })
    }
}

答案 1 :(得分:0)

原始代码可以在现代Rust中按原样编译,这大概是由于对non-lexical lifetimes所做的更改。也可以进行一些惯用的小更改:

#[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,
        }
    }
}

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 piece_iter = table.pieces.iter();
        let piece = piece_iter.next();
        let buf_iter = piece.map(|p| table.piece_buf(p).iter());
        PieceTableIterator {
            table,
            buf_iter,
            piece_iter,
        }
    }
}

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

    fn next(&mut self) -> Option<u8> {
        let iter = self.buf_iter.as_mut()?;

        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
                })
            })
            .copied()
    }
}

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);
    }
}