<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                這篇教程是現行3個Rust所有權系統之一。所有權系統是Rust最獨特且最引人入勝的特性之一,也是作為Rust開發者應該熟悉的。Rust所追求最大的目標 -- 內存安全,關鍵在于所有權。所有權系統有一些不同的概念,每個概念獨自成章: * [所有權](http://kaisery.gitbooks.io/rust-book-chinese/content/content/5.8.Ownership%20%E6%89%80%E6%9C%89%E6%9D%83.md),關鍵章節 * 借用,你正在閱讀的這個章節 * [生命周期](http://kaisery.gitbooks.io/rust-book-chinese/content/content/5.10.Lifetimes%20%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.md),關于借用的高級概念 這3章依次互相關聯,你需要完整地閱讀全部3章來對Rust的所有權系統進行全面的了解。 ## 原則(Meta) 在我們開始詳細講解之前,這有兩點關于所有權系統重要的注意事項。 Rust注重安全和速度。它通過很多_零開銷抽象_(_zero-cost abstractions_)來實現這些目標,也就是說在Rust中,實現抽象的開銷盡可能的小。所有權系統是一個典型的零開銷抽象的例子。本文提到所有的分析都是**在編譯時完成的**。你不需要在運行時為這些功能付出任何開銷。 然而,這個系統確實有一個開銷:學習曲線。很多Rust初學者會經歷我們所謂的“與借用檢查器作斗爭”的過程,也就是指Rust編譯器拒絕編譯一個作者認為合理的程序。這種“斗爭”會因為程序員關于所有權系統如何工作的基本模型與Rust實現的實際規則不匹配而經常發生。當你剛開始嘗試Rust的時候,你很可能會有相似的經歷。然而有一個好消息:更有經驗的Rust開發者反應,一旦他們適應所有權系統一段時間之后,與借用檢查器的沖突會越來越少。 記住這些之后,讓我們來學習關于借用的內容。 ## 借用 在[所有權](http://doc.rust-lang.org/nightly/book/ownership.html)章節的最后,我們有一個看起來像這樣的糟糕的函數: ~~~ fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) { // do stuff with v1 and v2 // hand back ownership, and the result of our function (v1, v2, 42) } let v1 = vec![1, 2, 3]; let v2 = vec![1, 2, 3]; let (v1, v2, answer) = foo(v1, v2); ~~~ 這并不是理想的Rust代碼,然而,因為它木有利用借用的優勢。這是它的第一步: ~~~ fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 { // do stuff with v1 and v2 // return the answer 42 } let v1 = vec![1, 2, 3]; let v2 = vec![1, 2, 3]; let answer = foo(&v1, &v2); // we can use v1 and v2 here! ~~~ 與其獲取`Vec`作為我們的參數,我們獲取一個引用:`&Vec`。并與其直接傳遞`v1`和`v2`,我們傳遞`&v1`和`&v2`。我們稱`&T`類型為一個”引用“,而與其擁有這個資源,它借用了所有權。一個借用變量的綁定在它離開作用域時并不釋放資源。這意味著`foo()`調用之后,我們可以再次使用原始的綁定。 引用是不可變的,就像綁定一樣。這意味著在`foo()`中,向量完全不能被改變: ~~~ fn foo(v: &Vec<i32>) { v.push(5); } let v = vec![]; foo(&v); ~~~ 有如下錯誤: ~~~ error: cannot borrow immutable borrowed content `*v` as mutable v.push(5); ^ ~~~ 放入一個值改變了向量,所以我們不允許這樣做 ## `&mut`引用 這有第二種類型的引用:`&mut T`。一個“可變引用”允許你改變你借用的資源。例如: ~~~ let mut x = 5; { let y = &mut x; *y += 1; } println!("{}", x); ~~~ 這會打印`6`。我們讓`y`是一個`x`的可變引用,接著把`y`指向的值加一。你會注意到`x`也必須被標記為`mut`,如果它不是,我們不能獲取一個不可變值的可變引用。 否則,`&mut`引用就像一個普通引用。這兩者之間_有_巨大的區別,以及它們如何交互的。你可以說在上面的例子中有些地方是可疑的,因為我們需要額外的作用域,包圍在`{`和`}`之間。如果我們移除它們,我們得到一個錯誤: ~~~ error: cannot borrow `x` as immutable because it is also borrowed as mutable println!("{}", x); ^ note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends let y = &mut x; ^ note: previous borrow ends here fn main() { } ^ ~~~ 它們被證明是規則。 ## 規則 Rust中的借用有一些規則: 第一,任何借用必須位于比擁有著更小的作用域。第二,你可以有一個或另一個這兩種類型的借用,不過不能同時擁有它們(這兩種): * 0個或N個資源的引用(&T) * 只有1個可變引用((&mut T) 你可能注意到這些非常的熟悉,雖然并不完全一樣,它類似于數據競爭的定義: > 當2個或更多個指針同時訪問同一內存位置,當它們中至少有1個在寫,同時操作并不是同步的時候存在一個“數據競爭” 通過引用,你可以擁有你像擁有的任意多的引用,因為它們沒有一個在寫。如果你在寫,并且你需要2個或更多相同內存的指針,則你只能一次擁有一個`&mut`。這就是Rust如何在編譯時避免數據競爭:我們會得到錯誤,如果我們打破規則的話。 在記住這些之后,讓我們再次考慮我們的例子。 ## 理解作用域(Thinking in scopes) 這是代碼: ~~~ let mut x = 5; let y = &mut x; *y += 1; println!("{}", x); ~~~ 這些代碼給我們如下錯誤: ~~~ error: cannot borrow `x` as immutable because it is also borrowed as mutable println!("{}", x); ^ ~~~ 這是因為我們違反了規則:我們有一個指向`x`的`&mut T`,所以我們不允許創建任何`&T`。一個或另一個。錯誤記錄提示了我們應該如何理解這個錯誤: ~~~ note: previous borrow ends here fn main() { } ^ ~~~ 換句話說,可變借用在剩下的例子中一直存在。我們需要的是可變借用在我們嘗試調用`println!`_之前_結束并生成一個不可變借用。在Rust中,借用綁定在借用有效的作用域上。而我們的作用域看起來像這樣: ~~~ let mut x = 5; let y = &mut x; // -+ &mut borrow of x starts here // | *y += 1; // | // | println!("{}", x); // -+ - try to borrow x here // -+ &mut borrow of x ends here ~~~ 這些作用域沖突了:我們不能在`y`在作用域中時生成一個`&x`。 所以我們增加了一個大括號: ~~~ let mut x = 5; { let y = &mut x; // -+ &mut borrow starts here *y += 1; // | } // -+ ... and ends here println!("{}", x); // <- try to borrow x here ~~~ 這就沒有問題了。我們的可變借用在我們創建一個不可變引用之前離開了作用域。不過作用域是看清一個借用持續多久的關鍵。 ## 借用避免的問題(Issues borrowing prevents) 為什么要有這些限制性規則?好吧,正如我們記錄的,這些規則避免了數據競爭。數據競爭能造成何種問題呢?這里有一些。 ### 迭代器失效(Iterator invalidation) 一個例子是“迭代器失效”,它在當你嘗試改變你正在迭代的集合時發生。Rust的借用檢查器阻止了這些發生: ~~~ let mut v = vec![1, 2, 3]; for i in &v { println!("{}", i); } ~~~ 這會打印出1到3.因為我們在向量上迭代,我們只得到了元素的引用。同時`v`本身作為不可變借用,它意味著我們在迭代時不能改變它: ~~~ let mut v = vec![1, 2, 3]; for i in &v { println!("{}", i); v.push(34); } ~~~ 這里是錯誤: ~~~ error: cannot borrow `v` as mutable because it is also borrowed as immutable v.push(34); ^ note: previous borrow of `v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `v` until the borrow ends for i in &v { ^ note: previous borrow ends here for i in &v { println!(“{}”, i); v.push(34); } ^ ~~~ 我們不能修改`v`因為它被循環借用。 ### 釋放后使用 引用必須與它引用的值活的一樣長。Rust會檢查你的引用的作用域來保證這是正確的。 如果Rust并沒有檢查這個屬性,我們可能意外的使用了一個無效的引用。例如: ~~~ let y: &i32; { let x = 5; y = &x; } println!("{}", y); ~~~ 我們得到這個錯誤: ~~~ error: `x` does not live long enough y = &x; ^ note: reference must be valid for the block suffix following statement 0 at 2:16... let y: &i32; { let x = 5; y = &x; } note: ...but borrowed value is only valid for the block suffix following statement 0 at 4:18 let x = 5; y = &x; } ~~~ 換句話說,`y`只在`x`存在的作用域中有效。一旦`x`消失,它變成無效的引用。為此,這個錯誤說借用“并沒有活的足夠久”因為它在應該有效的時候是無效的。 當引用在它引用的變量_之前_聲明會導致類似的問題: ~~~ let y: &i32; let x = 5; y = &x; println!("{}", y); ~~~ 我們得到這個錯誤: ~~~ error: `x` does not live long enough y = &x; ^ note: reference must be valid for the block suffix following statement 0 at 2:16... let y: &i32; let x = 5; y = &x; println!("{}", y); } note: ...but borrowed value is only valid for the block suffix following statement 1 at 3:14 let x = 5; y = &x; println!("{}", y); } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看