首页 文章

为什么iter()将列表借用为不可变的?

提问于
浏览
0

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元素的引用 .

1 回答

  • 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 object 's. Therefore you can' t可变地借用(对于 pop 方法),而 Iter 是活 .

    这是有充分理由的;如果 pop 成功,那么迭代器就会对前一个头部有一个悬空引用,导致内存不安全 .

相关问题