<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 生命周期 > [lifetimes.md](https://github.com/rust-lang/rust/blob/master/src/doc/book/lifetimes.md) commit f4fac9b0fa55d253b438eccdf1794baace6c9efe 這篇教程是現行 3 個 Rust 所有權系統之一。所有權系統是 Rust 最獨特且最引人入勝的特性之一,也是作為 Rust 開發者應該熟悉的。Rust 所追求最大的目標 -- 內存安全,關鍵在于所有權。所有權系統有一些不同的概念,每個概念獨自成章: - [所有權](#),關鍵章節 - [借用](#),以及它關聯的特性: "引用" (references) - 生命周期,你正在閱讀的這個章節 這 3 章依次互相關聯,你需要完整地閱讀全部 3 章來對 Rust 的所有權系統進行全面的了解。 ### 原則(Meta) 在我們開始詳細講解之前,這有兩點關于所有權系統重要的注意事項。 Rust 注重安全和速度。它通過很多*零開銷抽象*(*zero-cost abstractions*)來實現這些目標,也就是說在 Rust 中,實現抽象的開銷盡可能的小。所有權系統是一個典型的零開銷抽象的例子。本文提到所有的分析都是**在編譯時完成的**。你不需要在運行時為這些功能付出任何開銷。 然而,這個系統確實有一個開銷:學習曲線。很多 Rust 初學者會經歷我們所謂的“與借用檢查器作斗爭”的過程,也就是指 Rust 編譯器拒絕編譯一個作者認為合理的程序。這種“斗爭”會因為程序員關于所有權系統如何工作的基本模型與 Rust 實現的實際規則不匹配而經常發生。當你剛開始嘗試 Rust 的時候,你很可能會有相似的經歷。然而有一個好消息:更有經驗的 Rust 開發者反映,一旦他們適應所有權系統一段時間之后,與借用檢查器的沖突會越來越少。 記住這些之后,讓我們來學習有關生命周期的內容。 ### 生命周期 借出一個其它人所有資源的引用可以是很復雜的。例如,想象一下下列操作: - 我獲取了一個某種資源的句柄 - 我借給你了一個關于這個資源的引用 - 我決定不再需要這個資源了,然后釋放了它,這時你仍然持有它的引用 - 你決定使用這個資源 噢!你的引用指向一個無效的資源。這叫做*懸垂指針*(*dangling pointer*)或者“釋放后使用”,如果這個資源是內存的話。 要修正這個問題的話,我們必須確保第四步永遠也不在第三步之后發生。Rust 所有權系統通過一個叫*生命周期*(*lifetime*)的概念來做到這一點,它定義了一個引用有效的作用域。 當我們有一個獲取引用作為參數的函數,我們可以隱式或顯式涉及到引用的生命周期: ~~~ // implicit fn foo(x: &i32) { } // explicit fn bar<'a>(x: &'a i32) { } ~~~ `'a`讀作“生命周期 a”。技術上講,每一個引用都有一些與之相關的生命周期,不過編譯器在通常情況讓你可以省略(也就是,省略,查看下面的[生命周期省略](#))它們。在我們講到它之前,讓我們拆開顯式的例子看看: ~~~ fn bar<'a>(...) ~~~ 之前我們討論了一些[函數語法](#),不過我們并沒有討論函數名后面的`<>`。一個函數可以在`<>`之間有“泛型參數”,生命周期也是其中一種。我們在[本書的后面](#)討論其他類型的泛型。不過現在讓我們著重看生命周期。 我們用`<>`聲明了生命周期。這是說`bar`有一個生命周期`'a`。如果我們有兩個引用參數,它應該看起來像這樣: ~~~ fn bar<'a, 'b>(...) ~~~ 接著在我們的參數列表中,我們使用了我們命名的生命周期: ~~~ ...(x: &'a i32) ~~~ 如果我們想要一個`&mut`引用,我們這么做: ~~~ ...(x: &'a mut i32) ~~~ 如果你對比一下`&mut i32`和`&'a mut i32`,他們是一樣的,只是后者在`&`和`mut i32`之間夾了一個`'a`生命周期。`&mut i32`讀作“一個`i32`的可變引用”,而`&'a mut i32`讀作“一個帶有生命周期'a的i32的可變引用”。 ### 在`struct`中 當你處理[結構體](#)時你也需要顯式的生命周期: ~~~ struct Foo<'a> { x: &'a i32, } fn main() { let y = &5; // this is the same as `let _y = 5; let y = &_y;` let f = Foo { x: y }; println!("{}", f.x); } ~~~ 如你所見,`struct`也可以有生命周期。跟函數類似的方法, ~~~ struct Foo<'a> { # x: &'a i32, # } ~~~ 聲明一個生命周期,接著 ~~~ # struct Foo<'a> { x: &'a i32, # } ~~~ 使用它。然而為什么這里我們需要一個生命周期呢?因為我們需要確保任何`Foo`的引用不能比它包含的`i32`的引用活的更久。 ### `impl`塊 讓我們在`Foo`中實現一個方法: ~~~ struct Foo<'a> { x: &'a i32, } impl<'a> Foo<'a> { fn x(&self) -> &'a i32 { self.x } } fn main() { let y = &5; // this is the same as `let _y = 5; let y = &_y;` let f = Foo { x: y }; println!("x is: {}", f.x()); } ~~~ 如你所見,我們需要在`impl`行為`Foo`聲明一個生命周期。我們重復了`'a`兩次,就像在函數中:`impl<'a>`定義了一個生命周期`'a`,而`Foo<'a>`使用它。 ### 多個生命周期 如果你有多個引用,你可以多次使用同一個生命周期: ~~~ fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str { # x # } ~~~ 這意味著`x`和`y`存活在同樣的作用域內,并且返回值也同樣存活在這個作用域內。如果你想要`x`和`y`有不同的生命周期,你可以使用多個生命周期參數: ~~~ fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { # x # } ~~~ 在這個例子中,`x`和`y`有不同的有效的作用域,不過返回值和`x`有相同的生命周期 ### 理解作用域(Thinking in scopes) 理解生命周期的一個辦法是想象一個引用有效的作用域。例如: ~~~ fn main() { let y = &5; // -+ y goes into scope // | // stuff // | // | } // -+ y goes out of scope ~~~ 加入我們的`Foo`: ~~~ struct Foo<'a> { x: &'a i32, } fn main() { let y = &5; // -+ y goes into scope let f = Foo { x: y }; // -+ f goes into scope // stuff // | // | } // -+ f and y go out of scope ~~~ 我們的`f`生存在`y`的作用域之中,所以一切正常。那么如果不是呢?下面的代碼不能工作: ~~~ struct Foo<'a> { x: &'a i32, } fn main() { let x; // -+ x goes into scope // | { // | let y = &5; // ---+ y goes into scope let f = Foo { x: y }; // ---+ f goes into scope x = &f.x; // | | error here } // ---+ f and y go out of scope // | println!("{}", x); // | } // -+ x goes out of scope ~~~ 噢!就像你在這里看到的一樣,`f`和`y`的作用域小于`x`的作用域。不過當我們嘗試`x = &f.x`時,我們讓`x`引用一些將要離開作用域的變量。 命名作用域用來賦予作用域一個名字。有了名字是我們可以談論它的第一步。 ### 'static 叫做`static`的作用域是特殊的。它代表某樣東西具有橫跨整個程序的生命周期。大部分 Rust 程序員當他們處理字符串時第一次遇到`'static`: ~~~ let x: &'static str = "Hello, world."; ~~~ 基本字符串是`&'static str`類型的因為它的引用一直有效:它們被寫入了最終庫文件的數據段。另一個例子是全局量: ~~~ static FOO: i32 = 5; let x: &'static i32 = &FOO; ~~~ 它在二進制文件的數據段中保存了一個`i32`,而`x`是它的一個引用。 ### 生命周期省略(Lifetime Elision) Rust支持強大的在函數體中的局部類型推斷,不過這在項簽名中是禁止的以便允許只通過項簽名本身推導出類型。然而,出于人體工程學方面的考慮,有第二個非常限制的叫做“生命周期省略”的推斷算法適用于函數簽名。它只基于簽名部分自身推斷而不涉及函數體,只推斷生命周期參數,并且只基于 3 個易于記憶和無歧義的規則,雖然并不隱藏它涉及到的實際類型,因為局部推斷可能會適用于它。 當我們討論生命周期省略的時候,我們使用*輸入生命周期和輸出生命周期*(*input lifetime and output lifetime.*)。*輸入生命周期*是關于函數參數的,而*輸出生命周期*是關于函數返回值的。例如,這個函數有一個輸入生命周期: ~~~ fn foo<'a>(bar: &'a str) ~~~ 這個有一個輸出生命周期: ~~~ fn foo<'a>() -> &'a str ~~~ 這個兩者皆有: ~~~ fn foo<'a>(bar: &'a str) -> &'a str ~~~ 有3條規則: - 每一個被省略的函數參數成為一個不同的生命周期參數。 - 如果剛好有一個輸入生命周期,不管是否省略,這個生命周期被賦予所有函數返回值中被省略的生命周期。 - 如果有多個輸入生命周期,不過它們當中有一個是`&self`或者`&mut self`,`self`的生命周期被賦予所有省略的輸出生命周期。 否則,省略一個輸出生命周期將是一個錯誤。 ### 例子 這里有一些省略了生命周期的函數的例子。我們用它們的擴展形式配對了每個省略了生命周期的例子。 ~~~ fn print(s: &str); // elided fn print<'a>(s: &'a str); // expanded fn debug(lvl: u32, s: &str); // elided fn debug<'a>(lvl: u32, s: &'a str); // expanded // In the preceding example, `lvl` doesn’t need a lifetime because it’s not a // reference (`&`). Only things relating to references (such as a `struct` // which contains a reference) need lifetimes. fn substr(s: &str, until: u32) -> &str; // elided fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded fn get_str() -> &str; // ILLEGAL, no inputs fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous fn get_mut(&mut self) -> &mut T; // elided fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded fn new(buf: &mut [u8]) -> BufWriter; // elided fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded ~~~
                  <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>

                              哎呀哎呀视频在线观看