在Learning Rust With Entirely Too Many Linked Lists中,iter()
创建一个迭代器:
impl<T> List<T> {
pub fn iter(&self) -> Iter<T> {
Iter { next: self.head.as_ref().map(|node| &**node) }
}
}
我尝试测试迭代器是否阻止对列表进行进一步修改:
let mut list = List::new();
list.push(1);
let mut iter = list.iter();
list.pop();
编译器报告错误:
list2.rs:114:1: 114:5 error: cannot borrow `list` as mutable because it is also borrowed as immutable [E0502]
list2.rs:114 list.pop();
^~~~
list2.rs:113:24: 113:28 note: previous borrow of `list` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `list` until the borrow ends
list2.rs:113 let mut iter = list.iter();
^~~~
看起来Rust确实会阻止不安全的操作,但是从语法上看,为什么list.iter()
借用了list
?在该方法中,它只返回head元素的引用。
答案 0 :(得分:5)
来自链接文章:
pub struct Iter<T> {
next: Option<&Node<T>>,
}
所以迭代器有一个引用。扩展以使生命周期更加明确:
pub struct Iter<'a, T> {
next: Option<&'a Node<T>>,
}
现在查看iter
方法:
impl<T> List<T> {
pub fn iter(&self) -> Iter<T> {
...
}
}
由于Rust的借阅规则也在宣言中停止,因此我明白了这一点。现在,如果我们将退出的类型放回去:
pub fn iter<'a>(&'a self) -> Iter<'a, T> {...}
由于只有&self
参数,返回值的生命周期相同。请参阅elided lifetimes documentation。
最终结果是Iter<'a, T>
与传递给iter()
方法的引用具有相同的生命周期 - 因此引用的生命周期必须至少与Iter
一样长。 {1}}对象。因此,当pop
还活着时,您无法可变地借用(Iter
方法)。
这是有充分理由的;如果pop
成功,那么迭代器就会有一个悬空引用前头,导致记忆不安全。