Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

引用&借用(References&Borrowing)

如上所示,Owership讓我們改變一個變量的值變得“複雜”,那能否像其他編程語言那樣隨意改變變量的值呢?答案是有的。

所有權系統允許我們通過“Borrowing”的方式達到這個目的。這個機制非常像其他編程語言中的“讀寫鎖”,即同一時刻,只能擁有一個“寫鎖”,或只能擁有多個“讀鎖”,不允許“寫鎖”和“讀鎖”在同一時刻同時出現。當然這也是數據讀寫過程中保障一致性的典型做法。只不過Rust是在編譯中完成這個(Borrowing)檢查的,而不是在運行時,這也就是為什麼其他語言程序在運行過程中,容易出現死鎖或者野指針的問題。

通過**&**符號完成Borrowing:

fn main() {
	let x: Vec<i32> = vec!(1i32, 2, 3);
	let y = &x;
	println!("x={:?}, y={:?}", x, y);
}

Borrowing(&x)並不會發生所有權moved,所以println可以同時訪問x和y。 通過引用,就可以對普通類型完成修改。

fn main() {
	let mut x: i32 = 100;
	{
		let y: &mut i32 = &mut x;
		*y += 2;
	}
	println!("{}", x);
}

###借用與引用的區別

借用與引用是一種相輔相成的關係,若B是對A的引用,也可稱之為B借用了A。

很相近對吧,但是借用一詞本意為要歸還。所以在Rust用引用時,一定要注意應該在何處何時正確的“歸回”借用/引用。 最後面的“高級”小節會詳細舉例。

###規則

  1. 同一作用域,特定數據最多隻有一個可變借用(&mut T),或者2。
  2. 同一作用域,特定數據可有0個或多個不可變借用(&T),但不能有任何可變借用。
  3. 借用在離開作用域後釋放。
  4. 在可變借用釋放前不可訪問源變量。

###可變性 Borrowing也分“不可變借用”(默認,&T)和“可變借用”(&mut T)。

顧名思義,“不可變借用”是隻讀的,不可更新被引用的內容。

fn main() {
	let x: Vec<i32> = vec!(1i32, 2, 3);

	//可同時有多個不可變借用
	let y = &x;
	let z = &x;
	let m = &x;

	//ok
	println!("{:?}, {:?}, {:?}, {:?}", x, y, z, m);
}

再次強調下,同一作用域下只能有一個可變借用(&mut T),且被借用的變量本身必須有可變性 :

fn main() {
	//源變量x可變性
	let mut x: Vec<i32> = vec!(1i32, 2, 3);

	//只能有一個可變借用
	let y = &mut x;
	// let z = &mut x; //錯誤
    y.push(100);

	//ok
	println!("{:?}", y);

	//錯誤,可變借用未釋放,源變量不可訪問
	// println!("{:?}", x);
}  //y在此處銷燬

###高級例子 下面的複雜例子,進行了詳細的註釋,即使看不懂也沒關係,可以在完成Lifetimes(生命週期)的學習後再仔細思考本例子。

fn main() {
	let mut x: Vec<i32> = vec!(1i32, 2, 3);

	//更新數組
	//push中對數組進行了可變借用,並在push函數退出時銷燬這個借用
    x.push(10);

    {
	    //可變借用1
	    let mut y = &mut x;
        y.push(100);

        //可變借用2,注意:此處是對y的借用,不可再對x進行借用,
        //因為y在此時依然存活。
        let z = &mut y;
        z.push(1000);

	    println!("{:?}", z); //打印: [1, 2, 3, 10, 100, 1000]
    } //y和z在此處被銷燬,並釋放借用。


	//訪問x正常
	println!("{:?}", x); //打印: [1, 2, 3, 10, 100, 1000]
}

####總結

  1. 借用不改變內存的所有者(Owner),借用只是對源內存的臨時引用。
  2. 在借用週期內,借用方可以讀寫這塊內存,所有者被禁止讀寫內存;且所有者保證在有“借用”存在的情況下,不會釋放或轉移內存。
  3. 失去所有權的變量不可以被借用(訪問)。
  4. 在租借期內,內存所有者保證不會釋放/轉移/可變租借這塊內存,但如果是在非可變租借的情況下,所有者是允許繼續非可變租借出去的。
  5. 借用週期滿後,所有者收回讀寫權限
  6. 借用週期小於被借用者(所有者)的生命週期。

備註:   借用週期,指的是借用的有效時間段。