借用

唯一的區別就是對象的字面形式仍然需要使用“,”來分割元素,而class語法不需要。。。。

通過前面的學習,我們知道了所有權可以有效避免程序在運行期間執行某些無效操作,對于某些我們希望可以寬容的繞過所有權的嚴格處理的方法就是——讓借出去的所有權歸還給自己。但是上篇對此所提到的做法并不優雅,實在是繁瑣,看看下面的邋遢的代碼段:

fn main(){
    let mut v1:Vec<i32> = vec![1,2,3];
    let mut v2:Vec<i32> = vec![4,5,6];
    /*
    **let answer:i32;
    **(v1, v2, answer) = giveBack(v1, v2);
    **error[E0070]: invalid left-hand side expression
    */
    let (v1, v2, answer) = giveBack(v1, v2);
    for num1 in v1{println!("{}", num1);}
    for num2 in v2{println!("{}", num2);}
    println!("{}", answer);
}

fn giveBack(v1:Vec<i32>, v2:Vec<i32>) -> (Vec<i32>, Vec<i32>, i32){
    println!("give back to you!");
    (v1, v2, 99)
}

就像看上去的那樣,而且如果利用模式賦值的話貌似左邊必須出現一個let?暫且拋開這個問題不提,下面聊聊rust中的借用和引用。

1.使用借用

我們可以使用借用改寫一下上面的那個例子:

fn main(){
    let v1:Vec<i32> = vec![1,2,3];
    let v2:Vec<i32> = vec![4,5,6];
    let answer:i32 = borrow(&v1, &v2);
    println!("{}", answer);
    for num1 in v1{
        println!("{}", num1);
    }
    for num2 in v2{
        println!("{}", num2);
    }
}

fn borrow(v1:&Vec<i32>, v2:&Vec<i32>) -> i32{
    99
}

通過上面的實際例子,我們就可以發現是使用借用的確是對所有權系統的一個很好的補充。當我們使用借用的時候,我們利用借用得到的變量對資源所做的改變會實際影響原先的變量,而且盡管我們利用借用所得到的變量會進入某些塊作用域中,但是在離開這個塊作用域的時候并不會使得借用變量所綁定的存儲在堆上的資源被銷毀。下面看個更加復雜的關于借用的例子:

fn main(){
    let vec1:Vec<i32> = vec![0; 20];
    let vec2:Vec<i32> = vec![0; 70];
    let total:usize = fun2(&vec1, &vec2);
    println!("{}", total);//90
    for num1 in vec1{
        print!("{} ", num1);//0 0 0 0 0.....
    }
    println!("");
    for num2 in vec2{
        print!("{} ", num2);//0 0 0 0 .....
    }
}

fn fun1(v:&Vec<i32>) -> usize{
    v.len()
}

fn fun2(v1:&Vec<i32>, v2:&Vec<i32>) -> usize{
    let length1:usize = fun1(v1);
    let length2:usize = fun1(v2);
    length1 + length2
}

題外話:vector數據類型不僅索引的數據類型是usize,而且利用對象方法len()獲得長度其數據類型也為usize。這里的問題是這樣的:如果把上面的代碼改成下面的樣子的話也能夠成功運行:

fn main(){
    let vec1:Vec<i32> = vec![0; 20];
    let vec2:Vec<i32> = vec![0; 70];
    let total:usize = fun2(&vec1, &vec2);
    println!("{}", total);//90
    for num1 in vec1{
        print!("{} ", num1);//0 0 0 0...
    }
    println!("");
    for num2 in vec2{
        print!("{} ", num2);//0 0 0 0 0...
    }
}

fn fun1(v:&Vec<i32>) -> usize{
    v.len()
}

fn fun2(v1:&Vec<i32>, v2:&Vec<i32>) -> usize{
    let length1:usize = fun1(&v1);
    let length2:usize = fun1(&v2);
    length1 + length2
}

通過上面的例子。我們能夠知道:對于fun2函數中的局部變量v1以及v2來說,他們都是引用數據類型的變量;但是為什么可以對一個引用再次利用&得到他的引用呢??

2.借用類型也是默認不可變的

對于一個借用數據類型的變量來說,默認情況下,我們不能夠對其進行任何會改變其值的行為,因為借用數據類型變量也是默認不可變的。但是如果你實在希望實現對借用類型進行值更改的操作的話,那么你只需要對其加上mut修飾就足夠了。但是對于希望函數的形參是一個可變的借用類型的話,那么不僅需要在聲明形參的時候像下面這樣聲明:variableName:&mut type,而且傳入的實參也得像下面這樣:&mut variableName。由此就要求variableName這個變量本身就得是可變的。下面舉一個例子:

fn main(){
    let mut v1:Vec<i32> = vec![1,2,3];
    let len:usize = borrow(&mut v1);
    println!("{}", len);//4
    for num in v1{
        print!("{} ", num);//1 2 3 9
    }
}

fn borrow(v:&mut Vec<i32>) -> usize{
    v.push(9);
    v.len()
}

3.關于借用所必須要注意的問題

  • 1.不可變借用也好,可變借用也罷,他們都得必須位于比擁有者更小的作用域。舉一個例子:
//例子拋出錯誤:error: `num` does not live long enough
fn main(){
    let borrow:&i32;
    let num:i32 = 9;
    borrow = #// 1 borrow occurs here
}//num dropped here while still borrowed

為什么借用必須位于比擁有者更小的作用域呢?這里做一個猜測:我們知道普通變量是存儲在棧里面的,而對于棧這種數據結構來說,先進后出是他的標志性特征,所以對于上面的例子來說borrow變量一定是后于num變量被銷毀的,在位置1處,borrow變量開始借用num,但是隨之就是main函數的結束,所以里面的變量都會被銷毀,根據銷毀順序那么也應該是先銷毀num,但是此時borrow還存在著,他跟num是綁定著的,所以將num銷毀的話,將會讓borrow找不著北 ,所以這種情況下會報錯。但是如果是先將borrow刪除的話,那么就是OK的。

  • 2.在同一個作用域下,對同一個資源不能同時存在不可變引用和可變引用。
//拋出錯誤:error[E0502]: cannot borrow `source` as mutable because it is also borrowed as immutable
fn main(){
    let mut source:i32 = 9;
    let immutable_borrow:&i32 = &source;
    let mutable_borrow:&mut i32 = &mut source;
}

從上面的例子,我們還能夠看出另外一點特性:那就是對于一個可變的變量來說,我們既可以為其創建不可變的引用;也可以為他創建可變的引用——當然了在同一個作用域中是不能夠同時出現的。但是對于一個不可變的變量來說,你就不能夠為其創建一個可變的引用。言歸正傳,回到拋出的錯誤:error[E0502]: cannot borrow source as mutable because it is also borrowed as immutable,錯誤提示已經很明顯了,就是說對于同一個資源來說不能夠同時對其的可變引用和不可變引用。那么這是為什么呢?對于可變引用,他可以改變引用的資源內容,但是對于我們的不可變引用來說,很顯然他接受不到資源的實時變化,而對于這種情況顯然是注重安全的rust所不能夠接受的,所以說這兩種引用不可以在同一塊作用域對同一個資源進行綁定。

  • 3.在同一個作用域下,對同一個資源只能夠有一個可變引用。
//拋出錯誤:error[E0499]: cannot borrow `num` as mutable more than once at a time
fn main(){
    let mut num:i32 = 9;
    let mutable_borrow1:&mut i32 = &mut num;
    let mutable_borrow2:&mut i32 = &mut num;
}

從拋出的錯誤信息來看,我們也可以很直觀的看出那就是對于同一個資源來說在同一塊作用域不能夠有多個可變引用。就目前而言,我并知道為什么rust需要這樣設計,以后在做解答吧。

  • 4.在同一個作用域下,雖然不能夠對同一個資源有多個可變引用,但是對同一個資源有多個不可變引用還是可以的。
fn main(){
    let mut num:i32 = 9;
    let immutable_borrow1:&i32 = #
    let immutable_borrow2:&i32 = #
}

對于這種情況,只能夠用情理之中來形容,所以不解釋。

4.隱式的不可變借用

直接看代碼吧,反正目前為止也解釋不了,記住即可:

fn main(){
    let mut num:i32 = 9;
    println!("{}", num);//輸出9 位置1
}

別小看了上面那乍看起來貌似簡單的代碼,其實吧它上面隱藏了某些細節,就比如說位置1處的代碼,其實在那里的num訪問其實是一種不可變的引用?
可以看一個應用例子:

//error[E0502]: cannot borrow `num` as immutable because it is also borrowed as mutable
fn main(){
    let mut num:i32 = 9;
    let mutable_borrow1:&mut i32 = &mut num;//mutable borrow accurs here
    println!("{}", num);//immutable borrow accurs here
}

上面這個例子拋出的錯誤信息也很明顯,說明了對于一條簡單的println!()語句中出現的變量來說,從更深層次角度來看是表明了這個變量是對資源的不可變式的引用。既然如此的話,由于在rust中規定了不能夠在同一個作用域中出現對同一塊資源即出現可變引用又出現不可變引用,所以這個例子會拋出錯誤。

當然,修改這個例子也很簡單,因為是由于在某一個時間段中即出現對同一個資源的可變引用又出現了不可變引用,所以我們對此做的補救措施就是將其中一個引用給銷毀,所以應該銷毀先出現的那個引用,怎么銷毀?利用一個塊作用域嘛,離開作用域后即自動被銷毀了。:

fn main(){
    let mut num:i32 = 8;
    {
        let mutable_borrow1:&mut i32 = &mut num;
        *mutable_borrow1 += 1;
    }
    println!("{}", num);//9
}

如上所示,即達到了我們所希望看到的結果。

END

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 從語法角度來看,instanceof似乎是檢查操作符左值和操作符右值的關系,不過呵呵呵,實際上在內部上檢查的是操作...
    BIGHAI閱讀 258評論 0 0
  • 通用編程概念 變量與可變性 變量默認不可變,如需要改變,可在變量名前加 mut 使其可變。例如:let mut a...
    soojade閱讀 12,589評論 2 30
  • apply、call、bind apply call借用他人的函數方法 網上文章雖多,大多復制粘貼,且晦澀難懂,我...
    sponing閱讀 2,022評論 2 32
  • 借用:當人們面臨資源稀缺時,就會通過借用相應的時間貨金錢來應對突發事件。從長遠來看,借用會進一步加劇稀缺。 管窺:...
    易秒閱讀 293評論 0 0
  • 1、 Identifiers UNIQUE:每行唯一NOT NULL:IMMUTABLE:once inserte...
    宇宙超人喵學長閱讀 370評論 0 0