2014-01-08 38 views
5

虽然试图实现一个产生可变引用链接列表元素的迭代器,但我偶然发现了一个奇怪的问题。借用vs可变借用生命期中奇怪的失败

这工作得很好:

impl<'a, T> Iterator<&'a T> for LinkedListIterator<'a, T>{ 
    fn next(&mut self) -> Option<&'a T> { 
     match self.current { 
      &Cell(ref x, ref xs) => {self.current = &**xs; Some(x)}, 
      &End     => None 
     } 
    } 
} 

但是,这并不正常工作;编译器说的self寿命太短,无法保证其内容可以安全地reborrowed:

impl<'a, T> Iterator<&'a mut T> for LinkedListMutIterator<'a, T>{ 
    fn next(&mut self) -> Option<&'a mut T> { 
     match self.current { 
      &Cell(ref mut x, ref mut xs) => {self.current = &mut **xs; Some(x)}, 
      &End       => None 
     } 
    } 
} 

我希望,要么两个例子的工作,或两者不这样做,但我不明白如何借东西的可变vs不可变会影响编译器检查生命周期的方式。当然,如果有足够长的时间可以安全借用,它的寿命足够长,以便能够安全地进行可变借用?

编辑:这里是两个迭代器的定义:

pub struct LinkedListIterator<'a, T> 
    current: &'a LinkedList<T> 
} 

pub struct LinkedListMutIterator<'a, T> { 
    current: &'a mut LinkedList<T> 
} 

LinkedLisk:

#[deriving(Eq, Clone)] 
pub enum LinkedList<T> { 
    Cell(T, ~LinkedList<T>), 
    End 
} 

对于文件的完整视图,请参阅https://github.com/TisButMe/rust-algo/blob/mut_iter/LinkedList/linked_list.rs

回答

2

请注意,已对于代码的两个不同位来说,忽略了LinkedListMutIterator的定义,这可能与任何真正的重现和剖析问题的尝试有关。


所以,我会尝试猜测发生了什么。

这里的编译器错误信息可能会误导你;在self的生命周期之外还有其他因素可能与此处有关。

特别是我怀疑借用检查器是抱怨,因为它试图确保您没有创建多个可变的借口,别名相同的状态。

  • 它的声音有多个不可改变借用到同一状态的...

  • ...但你不能有多个可变的,借到同一状态的(因为我们要确保如果你有一个&mut引用某个状态,那么该引用是改变状态的唯一方法)。

+0

添加了您建议的信息。 我不明白我在哪里可变地借用XS在其他地方?唯一的其他&mut指针是存储在结构中的_current_指针,它指向列表中的前一个元素,而不是xs。 –

+0

我认为迭代代码最多访问链表*的每个单元*的证明超出了借用检查器的功能。你和我知道'next'会将迭代器的光标更新到链表中,从而确保你不会从'next'返回两次'&mut'指针(这会引入非法的混淆),但我不认为借款支票可以这种方式推理......但我还没有仔细检查借款支票对此案件的处理情况。 – pnkfelix

+0

同意。那么有没有什么办法可以避免使用不安全的指针呢? –

相关问题