2015-01-16 210 views
1
fn t(x: &mut u8) -> &mut u8 { 
    x 
} 

fn main() { 
    let mut x = 5u8; 
    let y = & mut x; 
    let z = t(y); 
    println!("{}", y); 
} 

編譯這給了我這個錯誤:參考作爲參數傳遞不動

main.rs:9:20: 9:21 error: cannot borrow `y` as immutable because `*y` is also borrowed as mutable 
main.rs:9  println!("{}", y); 

我還以爲y會調用t期間被移動,然後回到z,導致error: use of moved value

  1. 爲什麼我會得到這個錯誤信息呢?
  2. 當引用作爲函數參數提供時,Rust是否會自動創建新的借位而不是傳遞所有權?
  3. 這種行爲的目的是什麼?
+0

參見[移動性情不定地借來的所有權(http://stackoverflow.com/q/27650188/155423 ) – Shepmaster

回答

3

您正在從函數返回一個可變參考。然而,Rust並不知道方法沒有保留那個指針的副本沒有返回該指針的一個子部分,它是一個結構體。這意味着在任何時候,指向的價值都可能發生變化,這在Rust中是一個很大的禁忌;如果允許的話,那麼你很容易造成內存錯誤。

Does Rust automatically create a new borrow

是的,鏽「重新借用」引用。

一個更好的例子需要【熊更復雜:

struct Thing { a: u8, b: u8 } 

fn t(x: &mut Thing) -> &mut u8 { 
    &mut x.a 
} 

fn main() { 
    let mut x = Thing { a: 5, b: 6 }; 
    let z = t(&mut x); 
    *z = 0; 
    // x.a = 0; // cannot assign to `x.a` because it is borrowed 
} 

這裏,t一個可變指針返回到該結構的一個子集。這意味着整個結構是借來的,我們不能改變它(除了通過z)。 Rust將這個邏輯應用於所有功能,並且不會嘗試識別您的t函數只是返回相同的指針。

+0

'鐵鏽不知道該方法沒有保存該指針的副本' - 由於該函數已經過去,不能說它的任何內容會在被調用後被釋放嗎? –

+1

只要'z'存在,'t'的簽名就會導致'y'被可變地借用。並且'z'直到'main'結尾都存在。 – PEPP

+0

@JV我更新了答案並刪除了引用的誤導部分。 – Shepmaster

0

通過與rustc --pretty=expanded編譯程序,我們可以看到,println!宏借用它的參數:

#![no_std] 
#[macro_use] 
extern crate "std" as std; 
#[prelude_import] 
use std::prelude::v1::*; 
fn t(x: &mut u8) -> &mut u8 { x } 

fn main() { 
    let mut x = 5u8; 
    let y = &mut x; 
    let z = t(y); 
    ::std::io::stdio::println_args(::std::fmt::Arguments::new({ 
                    #[inline] 
                    #[allow(dead_code)] 
                    static __STATIC_FMTSTR: 
                     &'static [&'static str] 
                     = 
                     &[""]; 
                    __STATIC_FMTSTR 
                   }, 
                   &match (&y,) { // <----- y is borrowed here 
                    (__arg0,) 
                    => 
                    [::std::fmt::argument(::std::fmt::String::fmt, 
                         __arg0)], 
                   })); 
}