【问题标题】:Why does iter() borrow the list as immutable?为什么 iter() 将列表借用为不可变的?
【发布时间】:2016-07-03 21:06:07
【问题描述】:

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呢?在方法中,它只是返回头部元素的引用。

【问题讨论】:

    标签: rust


    【解决方案1】:

    来自链接的文章:

    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> {...}
    

    由于只有一个&amp;self 参数,因此返回值具有相同的省略生命周期。请参阅elided lifetimes documentation

    最终结果是 Iter&lt;'a, T&gt; 与传递给 iter() 方法的引用具有相同的生命周期 - 因此引用的生命周期必须至少延长到 Iter 对象的生命周期。因此,当Iter 存在时,您不能可变地借用(对于pop 方法)。

    这是有充分理由的;如果 pop 成功,则迭代器将对前一个头产生悬空引用,从而导致内存不安全。

    【讨论】:

      猜你喜欢
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      • 2016-05-02
      • 2015-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多