在迭代过程中推送到向量时,Rust会保护我免于迭代器失效吗?

时间:2018-03-11 22:38:19

标签: vector iterator rust invalidation

Rust会保护我免受迭代器失效的影响吗?或者我对realloc幸运吗?为&'a Vec<T>返回的迭代器给出了什么保证?

fn main() {
    let mut v = vec![0; 2];

    println!("capacity: {}", v.capacity());

    {
        let v_ref = &mut v;
        for _each in v_ref.clone() {
            for _ in 0..101 {
                (*v_ref).push(1); // ?
            }
        }
    }

    println!("capacity: {}", v.capacity());
}

1 个答案:

答案 0 :(得分:4)

在Rust中,大多数方法都会将&self - 引用转换为自我。在大多数情况下,内部some_string.len()之类的呼叫会扩展&#34;这样的事情:

let a: String = "abc".to_string();
let a_len: usize = String::len(&a); // This is identical to calling `a.len()`.

但是,请考虑对对象的引用:a_ref,它是引用&String的{​​{1}}。 Rust非常聪明,可以确定是否需要添加或删除引用,如上所述(a变为a);在这种情况下,&a会扩展为:

a_ref.len()

请注意,这基本上与原始示例相同,只是我们直接使用let a: String = "abc".to_string(); let a_ref: &String = &a; let a_len: usize = String::len(a_ref); // This is identical to calling `a_ref.len();`. Since `a_ref` is a reference already, it doesn't need to be altered. 而不是a的显式设置引用。

这意味着a扩展为v.clone(),类似地,Vec::clone(&v)扩展为v_ref.clone(),而且Vec::clone(v_ref)v_ref(或,具体而言,&v),我们可以将其简化为&mut v。换句话说,这些调用等效 - 在对象的基本引用(Vec::clone(&v))上调用clone()不会克隆引用,它克隆引用的对象

换句话说,Tamas Hedgeus&#39;评论是正确的:您正在迭代一个新的向量,该向量包含& 中元素克隆的元素。在v循环中迭代的项目不是for,而是&VecVec分开,因此迭代器失效不是问题

至于你关于Rust提供的保证的问题,你会发现Rust的借用检查程序处理得相当好而没有任何附加条件。

但如果您remove clone() from the for loop,,则会收到一条错误消息v,因为use of moved value: '*v_ref'被视为已被移动&#39;迭代它时进入v_ref循环,不能用于函数的其余部分;为了避免这种情况,for函数创建了一个迭代器对象,只有借用向量,允许您在循环结束后重用向量(并删除迭代器)。如果您在没有iter抽象的情况下尝试iterating over and mutating v,则错误会显示为v_refcannot borrow 'v' as mutable because it is also borrowed as immutable在由v生成的迭代器中不可靠地借用(其类型签名为v.iter() - 注意,它使借用到向量),并且不允许你因为Rust的借用检查器而改变向量,直到迭代器被删除(在fn iter(&self) -> Iter<T>循环结束时)。但是,由于您可以对单个对象进行多次不可变引用,因此您仍然可以从for循环中的向量读取,而不是写入它。

如果在迭代向量时需要改变向量的元素,可以使用iter_mut,它将 mutable 引用返回到一个元素一段时间,让你只改变 的元素。你仍然无法使用for来改变迭代向量本身,因为Rust确保一次只有一个可变引用对象,并确保没有可变引用与该对象的不可变引用在同一范围内的对象。