2017-02-15 58 views
2

this github discussion你覺得這個代碼,吸引借檢查的憤怒:如何在向量爲空時插入值時避免向量的多個可變借入?

fn main() { 
    let mut vec = vec!(); 

    match vec.first() { 
     None => vec.push(5), 
     Some(v) => unreachable!(), 
    } 
} 

我明白爲什麼有突變,而不變的是借力優秀是有問題的。我認爲一個解決方案是明確只有一個借位(一個可變的一個),但仍造成了有兩個借閱,一個不變的借,然後一個可變借我:

fn main() { 
    let mut vec: Vec<i32> = vec!(); 

    let r_vec: &mut Vec<i32> = &mut vec; 

    match r_vec.first() { 
     None => r_vec.push(5), 
     Some(v) => unreachable!(), 
    } 
} 

編譯器仍然不快樂:

error[E0502]: cannot borrow `*r_vec` as mutable because it is also borrowed as immutable 
--> testrust.rs:7:17 
    | 
6 |  match r_vec.first() { 
    |   ----- immutable borrow occurs here 
7 |   None => r_vec.push(5), 
    |     ^^^^^ mutable borrow occurs here 
8 |   Some(v) => unreachable!(), 
9 |  } 
    |  - immutable borrow ends here 

爲什麼我的解決方法無效,以及解決此問題的正確方法是什麼?

回答

5

你不知道。那麼,你「避免」有多重借款......沒有多重借款。

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

    if vec.first().is_none() { 
     vec.push(5); 
    } 
} 

更地道:

if vec.is_empty() { 
    vec.push(5); 
} 

在這兩種情況下,我們借用vec,使方法調用,而是終止執行if主體之前借用。比較一下match,其中借用匹配表達式進行借用,然後與匹配武器共享。


採取可用於兩種情況

這不是它是如何工作的一個可變借。你必須瞭解記憶是如何發揮和參考的。 A Vec包含指向存儲數據的內存的指針。

當您獲得對矢量數據的引用時,引用將保存數據的內存地址,並且編譯器確保只允許其中一個允許變更Vec。當你push的值,可能需要分配新的內存來存儲所有的數據。這可能會使您持有的引用無效。如果要發生,那麼接下來你使用的參考時間,它會指向一些其他不相關的一塊內存,程序就會崩潰,您的用戶數據將被暴露安全漏洞,等等,等等等等


issue you linked和相關pre-RFC的整個要點是,這些代碼應該能夠被確定爲安全:

match vec.first() { 
    None => vec.push(5), 
    Some(v) => unreachable!(), 
} 

在這種情況下,程序員可以看到,我們從來不使用在None的案例中借用,所以編譯器可以理論在執行任何配對武器之前結束借用或以其他方式使兩臂在生命期間脫節。它現在不這樣做

然而,在你的代碼版本,它實際上是更糟。通過明確採取借貸並將其保留在變量中,您可能會延長借款需要保留的時間,迫使它們重疊。

目前,唯一的解決方案是重新排序您的代碼人爲限制借入。在實踐中,我還沒有發現這非常煩人,因爲通常情況下有更好的代碼組織。

參見: