簡體   English   中英

Rust 抱怨釋放了可變借用但不是不可變借用

[英]Rust complains about freed mutable borrow but not immutable borrow

除了一個返回不可變引用而另一個返回可變引用之外,以下兩個 Rust 函數是相同的。 由於兩者都不涉及多次借用某些東西,所以我不明白為什么兩者的工作方式有任何不同。 但是,具有可變引用的會導致編譯錯誤,而具有不可變引用的則不會:

// This complies with no problems
fn foo<'a>() {
    let _: &'a () = &();
}

// This does not compile (see error below)
fn foo_mut<'a>() {
    let _: &'a mut () = &mut ();
}
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:14:30
   |
13 | fn foo_mut<'a>() {
   |            -- lifetime `'a` defined here
14 |     let _: &'a mut () = &mut ();
   |            ----------        ^^ creates a temporary which is freed while still in use
   |            |
   |            type annotation requires that borrow lasts for `'a`
15 | }
   |  - temporary value is freed at the end of this statement

For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground` due to previous error

這也可能是相關的,當沒有明確的生命周期時,代碼也沒有編譯問題:

// This also compiles with no problem
fn foo_mut_without_lifetime() {
    let _: &mut () = &mut ();
}

似乎唯一導致問題的是嘗試存儲具有生命周期的可變引用,而不可變引用和沒有顯式生命周期的引用沒有問題。 為什么會發生這種情況,我該如何解決?

請注意,這里()或通用生命周期沒有什么特別之處。 這編譯得很好:

fn allowed() -> &'static i32 {
    let x = &3;
    let y: &'static i32 = x;
    y
}

這不會:

fn not_allowed() -> &'static mut i32 {
    let x = &mut 3;
    let y: &'static mut i32 = x;
    y
}

那么為什么允許不可變引用呢?

當您引用一個值時,Rust 會根據該值將消亡的位置推斷其生命周期。 這是一個例子:

let y;
{
    let x = 3;
    y = &x;
    println!("{y}"); // works fine, `y` is still alive
} // `x` will get dropped at the end of this block
println!("{y}"); // fails to compile, the lifetime of `y` has expired (since `x` has died)

由於x在塊的末尾死亡,Rust 知道y引用的生命周期也應該只延伸到塊的末尾。 因此,它會阻止您在x死后使用它。

這似乎很明顯。 但是花點時間想一想。 在以下代碼中:

let x;
{ // block A
x = &3;
}

x的推斷生命周期是多少? 您可能會想說“與塊 A 相同”。 但這實際上是不正確的。 為什么? 因為 Rust 比那更聰明。 它知道3是一個常量,因此 Rust 可以將3放入最終可執行文件的常量表中。 並且由於常量表將與最終程序的生命周期一樣長, Rust 可以推斷表達式&3具有'static生命周期。 然后一切正常,因為&'static可以根據需要轉換為任何其他生命周期!

Rust 在常量和臨時變量之間划清界限,擁有常量表達式的好處之一是采用任何常量的不可變引用將始終產生'static生命周期”。 這不是臨時的。 以下代碼將無法編譯:

fn f() -> &'static String {
    let x = &String::new();
    let y: &'static String = x;
    y
}

這是因為對於臨時對象,Rust 不能將它們放在可執行文件的常量表中,因為它們必須按需計算,因此與它們所在的范圍共享相同的生命周期。

好的,這很好,但是為什么不允許常量的可變引用是'static

允許這樣做有兩個問題:

  1. 在某些體系結構上,無法修改常量表。 WASM 和一些嵌入式架構以及所有哈佛架構機器都是如此。 提供&mut引用完全是胡說八道,因為它們是不可變的。 這種基本的借用檢查器規則在平台之間應該沒有區別。

  2. &'static mut引用是危險的,因為它實際上是一個全局變量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM