最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

rust中生命周期使用

 更新時間:2026年07月05日 11:03:31   作者:大口吃飯大口吐  
本文介紹了Go、C和Rust三種語言處理內(nèi)存安全的不同機制,文章還詳細對比了Rust中所有權(quán)類型和引用類型的區(qū)別,并說明了生命周期標注的基本語法規(guī)則,感興趣的可以了解一下

以這段Go代碼為例作為開場

func createInt() *int {
    i := 42   // int 類型分配在棧上
    return &i // 這里由于返回引用類型,分配到堆上
} 
func main() {
    num := createInt()
    println(*num)  // 程序結(jié)束時,num指向的堆內(nèi)存會被釋放
}

這是一段Go程序,是健康可運行的,createInt函數(shù)返回指針,main函數(shù)調(diào)用,這里叫做 內(nèi)存逃逸

Go語言中的Gc回收器+逃逸分析,這兩個東西組合保障了程序能夠正常運行,且不必要擔心安全問題

當這段逃逸的堆內(nèi)存沒有地方再引用時,會被回收掉

懸垂引用

一個引用(或指針)仍然指向一塊內(nèi)存地址,但這塊內(nèi)存已經(jīng)被釋放或不再有效。此時再繼續(xù)操作程序就會異常

下面是一個C語言例子

#include <stdio.h>
int* createInt() {
    int i = 42;      // int 類型分配在棧上
    return &i;       // 返回 i 的地址
}                    // ?? 函數(shù)結(jié)束,棧的內(nèi)存會被回收
int main() {
    int* num = createInt();  // 接收了已釋放內(nèi)存的地址(
    printf("%d\n", *num);    // ?? 未定義行為!可能打印 42,也可能打印垃圾值,或者崩潰
    return 0;
}

C語言沒Go那一套逃逸分析的自動堆內(nèi)存分配機制,這里的代碼實現(xiàn)就稱為 懸垂引用,或野指針

如果再C語言中實現(xiàn)該邏輯,需要手動將函數(shù)createInt返回內(nèi)容分配到堆上,為什么要分配到堆上?

因為棧的東西在函數(shù)執(zhí)行完就被回收了,注意哈,C語言沒有Gc回收機制,但棧上的內(nèi)存操作系統(tǒng)是會自動管理的

改良后的完整代碼

#include <stdio.h>
#include <stdlib.h>  // 包含malloc/free的頭文件
int* createInt() {
    int* i = (int*)malloc(sizeof(int));  // 分配堆內(nèi)存
    if (i == NULL) {  // 檢查內(nèi)存分配是否成功(必做)
        printf("內(nèi)存分配失敗\n");
        exit(1);
    }
    *i = 42;          // 給堆內(nèi)存賦值
    return i;         // 返回堆內(nèi)存地址(安全)
}
int main() {
    int* num = createInt();
    printf("%d\n", *num);  // 輸出 42(安全)
    free(num);             // 釋放堆內(nèi)存(避免內(nèi)存泄漏)
    num = NULL;            // 置空指針(避免野指針)
    return 0;
}

rust中懸垂引用

概念都是一樣的,rust中沒有C語言的malloc/free,沒有Go語言的Gc/逃逸分析

fn main() {
    let i = create_int();
    println!("{}", i);
}

fn create_int() -> &i32 {
    let s = 32;
    &s
}

rust的編譯器不僅僅用來轉(zhuǎn)換二進制代碼,還提供了代碼解決方案,這是完整的報錯信息,里面已經(jīng)提示你正確的代碼書寫方式

error[E0106]: missing lifetime specifier
  --> src/main.rs:12:20
   |
12 | fn create_int() -> &i32 {
   |                    ^ expected named lifetime parameter
   |
   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
   |
12 | fn create_int() -> &'static i32 {
   |                     +++++++
help: instead, you are more likely to want to return an owned value
   |
12 - fn create_int() -> &i32 {
12 + fn create_int() -> i32 {
   |

For more information about this error, try `rustc --explain E0106`.
error: could not compile `naive` (bin "naive") due to 1 previous error

rust中解決懸垂引用的方法為,-> 生命周期

rust 兩大數(shù)據(jù)類型

在搞清楚生命周期之前,要先區(qū)分兩大類型

  • 所有權(quán)類型:你是數(shù)據(jù)的“主人”,數(shù)據(jù)存在你的變量里
  • 引用類型:你只是數(shù)據(jù)的“借閱者”,數(shù)據(jù)屬于別人,你只能看或改,不能銷毀它
fn main() {
    let i = create_int();
    let j = create_intptr(); // 會報錯
}

// 32 這個值是變量 s 的,該函數(shù)返回的是 s,誰接收誰能隨便用
// 不管你是堆還是棧分配,所有權(quán)會自動管理
fn create_int() -> i32 {
    let s = 32;
    s
}

// 32 這個值是變量 s 的,該函數(shù)返回的是 s 的引用指針,接收方只能看/改
// 但是,函數(shù)create_intptr執(zhí)行結(jié)束了,s 釋放銷毀了,main函數(shù)中的 j 將變成懸垂引用
fn create_intptr() -> &i32 {
    let s = 32;
    &s
}

換句話來說,

在局部塊兒(函數(shù)、結(jié)構(gòu)體…)返回引用類型,會產(chǎn)生懸空指針;返回所有權(quán)類型,可以隨便玩

rust 中解決懸空指針的方法為 -> 生命周期

這里整理了一份 所有權(quán)類型 和 引用類型 的具體體現(xiàn)

所有權(quán)類型

特征:變量直接包含數(shù)據(jù)(或在堆上擁有數(shù)據(jù)),當變量離開作用域時,數(shù)據(jù)會被自動釋放(Drop)。
符號:通常沒有 & 符號。

類別具體類型示例說明
基本標量類型i32, f64, bool, char這些類型大小固定,直接存儲在棧上。賦值時會復制一份新數(shù)據(jù)。
元組 (Tuple)(i32, bool), (String, i32)如果元組內(nèi)包含擁有所有權(quán)的類型,元組本身也擁有它們。
數(shù)組 (Array)[i32; 5], ["a", "b"]大小固定,直接存儲在棧上(除非很大)。賦值時復制。
結(jié)構(gòu)體 (Struct)struct User { name: String }如果結(jié)構(gòu)體字段是 String 等擁有所有權(quán)的類型,結(jié)構(gòu)體實例就擁有這些數(shù)據(jù)。
枚舉 (Enum)enum Option<T> { Some(T), None }同上,擁有內(nèi)部數(shù)據(jù)的所有權(quán)。
字符串 (String)String::from("hello")重點:這是堆分配的字符串,變量擁有堆上數(shù)據(jù)的所有權(quán)。
集合 (Collections)Vec<T>, HashMap<K, V>, Box<T>這些都在堆上分配數(shù)據(jù),變量擁有堆數(shù)據(jù)的句柄(指針+容量+長度),負責釋放內(nèi)存。
閉包 (Closure)|x| x + 1 (捕獲所有權(quán)時)閉包可以捕獲變量的所有權(quán)。

代碼示例

let a = 10;                 // a 擁有 10
let s = String::from("hi"); // s 擁有堆上的 "hi"
let v = vec![1, 2, 3];      // v 擁有堆上的數(shù)組
let my_struct = User { name: s }; // my_struct 現(xiàn)在擁有了 name (s 的所有權(quán)轉(zhuǎn)移了)

引用類型

特征:變量不包含數(shù)據(jù),只包含數(shù)據(jù)的地址。它們不負責釋放內(nèi)存。必須依附于某個擁有所有權(quán)的變量存在。
符號:必須帶有 & (不可變引用) 或 &mut (可變引用)。

類別具體類型示例說明
不可變引用&i32, &String, &str只能讀數(shù)據(jù),不能改??梢杂卸鄠€同時存在。
可變引用&mut i32, &mut Vec<i32>可以修改數(shù)據(jù)。同一時間只能有一個。
切片 (Slices)&[i32], &str重點:切片是對連續(xù)內(nèi)存部分的引用。&str 是對字符串數(shù)據(jù)的引用(通常指向 String 內(nèi)部或字面量)。
原始指針*const T, *mut T類似 C 的指針,不安全(unsafe),但也屬于引用語義(不擁有所有權(quán))。

代碼示例

let a = 10;
let r = &a;            // r 是引用,借用 a,r 的類型是 &i32

let st = "hello";      // 注意:st是引用類型,引用的一個 "hello" 的串,"hello" 這個字符并不屬于變量 st


let s = String::from("hello");
let slice: &str = &s;  // slice 是引用,借用 s 的一部分,類型是 &str

let mut x = 5;
let m = &mut x;        // m 是可變引用,類型是 &mut i32
*m = 10;               // 通過引用修改數(shù)據(jù)

rust 生命周期

生命周期是編譯器用來確保所有引用都是有效的機制。它們的主要目的是防止懸垂引用,即引用指向了已經(jīng)被釋放的內(nèi)存

語法規(guī)則

生命周期標注以 ’ 開頭,通常使用小寫字母,如 'a, 'b, 'c, 'static 等。通常會搭配泛型符號使用。

rust中,泛型不僅僅能用來定義自定義類型,也可用于自定義生命周期類型

static是一個特殊的關(guān)鍵字,下面會單獨說

不使用生命周期,會報錯

fn main() {
    let st = longest("hello", "world");
    println!("{}", st);
}

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}

加上生命周期

fn main() {
    let st = longest("hello", "world");
    println!("{}", st);
}

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

這里聲明了一個生命周期為'a的泛型,返回的引用也使用了'a生命周期,這樣就保證了返回的引用指向的數(shù)據(jù)和傳入的引用指向的數(shù)據(jù)是同一個生命周期,不會出現(xiàn)懸垂引用

拓展

結(jié)構(gòu)體類型使用

struct Excerpt<'a> {
    part: &'a str,
}

// impl 方法實現(xiàn)中也需聲明生命周期: impl<'a> xxx<'a>
impl<'a> Excerpt<'a> {
    fn return_str(&self, announcement: &str) -> &str {
        println!("Announcement: {}", announcement);
        self.part // 返回的是 self 的一部分,生命周期與 self 綁定
    }
}

fn main() {
    let st = Excerpt { part: "hello" };
    println!("{}", st.return_str("world"));
}

多個生命周期

fn get_first<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
    y // 明確返回的是 x 的切片,與 y 的生命周期無關(guān) 返回x可編譯成功,返回y會編譯失敗
}

fn main() {
    let st = get_first("hello", "world");
    println!("{}", st);
}

'static 生命周期

系統(tǒng)預設的一個特殊的生命周期,表示該引用在整個程序運行期間都有效。(那怕是聲明方的程序已經(jīng)?;厥樟?

以字面量字符引用為例let s = "world";,這個類型編輯器顯示是&str類型,這里其實給省略了,它應當是一個定義了全局生命周期的&'static str類型。

案例_1

// 報錯
fn longest_1() -> &str {
    let s = "world";
    s
}

// 正常
fn longest_2(x: &str) -> &str {
    let y = "world";
    y
}

這是因為rust編譯器存在一套生命周期省略規(guī)則,有一條規(guī)則為 如果函數(shù)有一個輸入引用參數(shù)(如 &str),且返回值是引用類型,編譯器會自動將返回值的生命周期推斷為與這個輸入?yún)?shù)的生命周期相同。

longest_1 手動聲明返回類型為 -> &'static str 可以編譯通過

這個除外,編譯器根據(jù)邏輯,不確定使用x還是y 的生命周期

fn longest_6(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}

案例_2

// 沒顯示聲明,任何生命周期都可以傳 'static 'a 'b
fn partial(s: &str) {
    println!("Static string: {}", s);
}

// 顯示聲明了 static 周期
fn global(s: &'static str) {
    println!("Static string: {}", s);
}

總結(jié)

各語言解決懸空指針的方法

  • Go 逃逸分析+Gc垃圾回收
  • C 手動分配堆內(nèi)存,手動回收
  • rust 生命周期

到此這篇關(guān)于rust中生命周期使用的文章就介紹到這了,更多相關(guān)rust 生命周期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Rust中不可變變量與const的區(qū)別詳解

    Rust中不可變變量與const的區(qū)別詳解

    Rust作者認為變量默認應該是immutable,即聲明后不能被改變的變量,這一點是讓跨語言學習者覺得很別扭,不過這一點小的改變帶來了諸多好處,本節(jié)我們來學習Rust中不可變變量與const的區(qū)別,需要的朋友可以參考下
    2024-02-02
  • Rust應用調(diào)用C語言動態(tài)庫的操作方法

    Rust應用調(diào)用C語言動態(tài)庫的操作方法

    這篇文章主要介紹了Rust應用調(diào)用C語言動態(tài)庫,本文記錄了筆者編寫一個簡單的C語言動態(tài)庫,并通過Rust調(diào)用動態(tài)庫導出的函數(shù),需要的朋友可以參考下
    2023-01-01
  • Rust 累計時間長度的操作方法

    Rust 累計時間長度的操作方法

    在Rust中,如果你想要記錄累計時間,通??梢允褂脴藴蕩熘械膕td::time::Duration類型,這篇文章主要介紹了Rust如何累計時間長度,需要的朋友可以參考下
    2024-05-05
  • Rust使用kind進行異常處理(錯誤的分類與傳遞)

    Rust使用kind進行異常處理(錯誤的分類與傳遞)

    Rust?有一套獨特的處理異常情況的機制,它并不像其它語言中的?try?機制那樣簡單,這篇文章主要介紹了Rust指南錯誤的分類與傳遞以及使用kind進行異常處理,需要的朋友可以參考下
    2022-09-09
  • Rust生成隨機數(shù)的項目實踐

    Rust生成隨機數(shù)的項目實踐

    Rust標準庫中并沒有隨機數(shù)生成器,常見的解決方案是使用rand包,本文主要介紹了Rust生成隨機數(shù)的項目實踐,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • rust實現(xiàn)post小程序(完整代碼)

    rust實現(xiàn)post小程序(完整代碼)

    這篇文章主要介紹了rust實現(xiàn)一個post小程序,本文通過示例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

    Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

    這篇文章主要介紹了Rust?use關(guān)鍵字妙用|模塊內(nèi)容拆分,文中還給大家介紹use關(guān)鍵字的習慣用法,快速引用自定義模塊內(nèi)容或標準庫,以此優(yōu)化代碼書寫,需要的朋友可以參考下
    2022-09-09
  • rust 包模塊組織結(jié)構(gòu)詳解

    rust 包模塊組織結(jié)構(gòu)詳解

    RUST提供了一系列的功能來幫助我們管理代碼,包括決定哪些細節(jié)是暴露的、哪些細節(jié)是私有的,以及不同的作用域的命名管理,這篇文章主要介紹了rust 包模塊組織結(jié)構(gòu)的相關(guān)知識,需要的朋友可以參考下
    2023-12-12
  • Rust中字符串類型&str和String的使用

    Rust中字符串類型&str和String的使用

    在Rust中,字符串是一種非常重要的數(shù)據(jù)類型,&str和String是Rust中兩種主要的字符串類型,本文主要介紹了Rust中字符串類型&str和String的使用,感興趣的可以了解一下
    2024-03-03
  • Rust實現(xiàn)grep命令行工具的方法

    Rust實現(xiàn)grep命令行工具的方法

    這篇文章主要介紹了Rust實現(xiàn)grep命令行工具的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07

最新評論

永吉县| 乌兰察布市| 定远县| 诏安县| 织金县| 达日县| 望都县| 和顺县| 平度市| 丹阳市| 栾城县| 自贡市| 广灵县| 博爱县| 鲜城| 山西省| 社旗县| 铁岭市| 荆州市| 禄丰县| 桂林市| 兴义市| 固阳县| 东辽县| 卓资县| 突泉县| 无极县| 榆中县| 博野县| 同德县| 静乐县| 凉山| 旅游| 峨山| 宁津县| 渑池县| 德钦县| 西乡县| 尖扎县| 铁力市| 望奎县|