rust--什么是生命周期?

// 什么是生命周期?
// 參考: https://doc.rust-lang.org/book/second-edition/ch10-03-lifetime-syntax.html
// 參考: https://stackoverflow.com/questions/31609137/why-are-explicit-lifetimes-needed-in-rust


// 核心: 生命周期只跟引用/借用有關(guān), 如果不是引用/借用, 那么就不存在生命周期的說(shuō)法,
//       因?yàn)榉且?借用都必然會(huì)產(chǎn)生所有權(quán)轉(zhuǎn)移, 所有權(quán)轉(zhuǎn)移會(huì)跳出scope的限制.


// 生命周期作用在function、method、trait 和 struct 中,
// 編譯器默認(rèn)情況下會(huì)為每個(gè)引用類型的參數(shù)自動(dòng)補(bǔ)充不同(為每個(gè)引用單獨(dú)增加一個(gè)'a/'b/'c)的生命周期,
// 只有出現(xiàn)它無(wú)法識(shí)別的情況時(shí), 才會(huì)報(bào)錯(cuò)并要求讓你自己來(lái)填寫生命周期.


// 什么情況下編譯器會(huì)自動(dòng)補(bǔ)充生命周期?
// 1. 當(dāng)參數(shù)含有多個(gè)引用, 且返回值類型不是引用時(shí), 編譯器會(huì)自動(dòng)為每個(gè)引用添加一個(gè)不同的聲明周期.
//    fn print(status: &i32, msg: &str) -> Message {};
//    編譯器自動(dòng)補(bǔ)充生命周期
//    fn print<'a, 'b>(status: &'a i32, msg: &'b i32) -> Message {};
fn multi_reference_parameters_and_return_value_is_not_reference_type() {

    #[allow(dead_code)]
    #[derive(Debug)]
    struct Message {
        status: i32,
        msg: String
    }

    // 不寫生命周期
    #[allow(unused_variables)]
    fn print1(status: &i32, msg: &str) -> Message {
        if status == &200 {
            Message {status: 200, msg: String::from("ok!")}
        } else {
            Message {status: 404, msg: String::from("page not found!")}
        }
    };

    // 寫生命周期
    #[allow(unused_variables)]
    fn print2<'a, 'b>(status: &'a i32, msg: &'b str) -> Message {
        if status == &200 {
            Message {status: 200, msg: String::from("ok!")}
        } else {
            Message {status: 404, msg: String::from("page not found!")}
        }
    }

    print1(&200, "ok!");
    print1(&404, "page not found!");

    print2(&200, "ok!");
    print2(&404, "page not found!");
}


// 2. 當(dāng)參數(shù)只含有一個(gè)引用類型, 那么編譯器會(huì)自動(dòng)補(bǔ)充生命周期, 如果返回值也是一個(gè)引用類型, 那么編譯器也會(huì)自動(dòng)給引用類型的返回值添加生命周期.
//    fn print(msg: &str) -> &str {}
//    編譯器自動(dòng)補(bǔ)充生命周期
//    fn print<'a>(msg: &'a str) -> &'a str {};
fn only_one_reference_parameter_and_return_value_type_is_reference_too() {

    // 不寫生命周期
    #[allow(unused_variables)]
    fn print1(status: i32, msg: &str) -> &str {
        if status == 200 {
            println!("{}", msg);
            msg
        } else {
            let s = "custom message";
            println!("{}", s);
            s
        }
    };

    // 寫生命周期
    #[allow(unused_variables)]
    fn print2<'a>(status: i32, msg: &'a str) -> &'a str {
        if status == 200 {
            println!("{}", msg);
            msg
        } else {
            let s = "custom message";
            println!("{}", s);
            s
        }
    }

    print1(200, "ok!");
    print1(404, "page not found!");

    print2(200, "ok!");
    print2(404, "page not found!");
}


// 3. 當(dāng)參數(shù)中含有 &self 或 &mut self 時(shí), 如果返回值也是一個(gè)引用類型, 那么編譯器會(huì)自動(dòng)給引用類型的返回值添加生命周期.
//    struct ImportantExcerpt<'a> {
//        part: &'a str,
//    }
//    impl<'a> ImportantExcerpt<'a> {
//        fn announce_and_return_part(&self, announcement: &str) -> &str {
//            println!("Attention please: {}", announcement);
//            self.part
//        }
//    }
//    編譯器自動(dòng)補(bǔ)充生命周期
//    struct ImportantExcerpt<'a> {
//        part: &'a str,
//    }
//    impl<'a> ImportantExcerpt<'a> {
//        fn announce_and_return_part(&'a self, announcement: &'a str) -> &'a str {
//            println!("Attention please: {}", announcement);
//            self.part
//        }
//    }
fn lifetime_on_method() {
    struct Message<'a> {
        id: &'a str,
        msg: &'a str,
    }

    // 不寫生命周期
    impl<'a> Message<'a> {
        fn get_msg_by_id1(&self, id: &str) -> &str {
            if self.id == id {
                println!("lifetime_on_method: {} {}", self.id, self.msg);
                self.msg
            } else {
                println!("lifetime_on_method: {} {}", id, self.msg);
                self.msg
            }
        }
    }
    let m = Message {id: "200", msg: "ok!"};
    m.get_msg_by_id1("200");
    m.get_msg_by_id1("404");

    // 寫生命周期
    impl<'a> Message<'a> {
        fn get_msg_by_id2(&'a self, id: &'a str) -> &'a str {
            if self.id == id {
                println!("lifetime_on_method: {} {}", self.id, self.msg);
                self.msg
            } else {
                println!("lifetime_on_method: {} {}", id, self.msg);
                self.msg
            }
        }
    }

    let m = Message {id: "200", msg: "ok!"};
    m.get_msg_by_id2("200");
    m.get_msg_by_id2("404");
}


// 什么情況下編譯器不會(huì)自動(dòng)補(bǔ)充生命周期?
// 當(dāng)參數(shù)含有大于一個(gè)引用類型, 并且返回值類型也是引用時(shí), 編譯器就要求必須填寫完整的生命周期.
fn error_example_that_compile_not_fill_lifetime() {        // 問(wèn)題代碼, 需注釋掉才能運(yùn)行
    fn print(status: &str, msg: &str) -> &str {          // 編譯器翻譯成 fn print<'a, 'b>(status: &'a str, msg: &'b str) -> &str {}
        if status == "200" {
            msg                                            // msg == &'b str        與   指定的 &str 不一致
        } else {
            status                                         // status == &'a str     與   指定的 &str 不一致
        }
    }

    print("200", "ok!");
    // error output: missing lifetime specifier, expected lifetime parameter.
    // 備注: 這個(gè)例子根本就不是比較生命周期的長(zhǎng)短問(wèn)題,
    //       而是實(shí)際返回值與指定返回值生命周期不一致的問(wèn)題.
    // 推理:
    //       1. 已知編譯器會(huì)自動(dòng)補(bǔ)充生命周期:
    //          fn print<'a, 'b>(status: &'a str, msg: &'b str) -> &str {}
    //          這是會(huì)報(bào)錯(cuò), 因?yàn)榫幾g器沒有給這個(gè)引用返回值類型補(bǔ)充生命周期,
    //          這是因?yàn)楫?dāng)返回值是一個(gè)引用時(shí), 必須包含生命周期.
    //
    //       2. 如果手動(dòng)生命生命周期:
    //          fn print<'a, 'b>(status: &'a str, msg: &'b str) -> &'a str {};
    //          這樣也會(huì)報(bào)錯(cuò), 這是因?yàn)檫壿嫶a塊里面不僅僅是返回 'a 這個(gè)生命周期里面的 status 引用變量,
    //          也有可能會(huì)返回 'b 生命周期里面的 msg 引用變量, 因此與指定的返回值 -> &'a str 不相符.
    //
    //       3. 唯一的解決辦法是, 認(rèn)為的鎖定引用的生命周期, 都在一個(gè)生命周期里面.
    //          fn print<'a>(status: &'a str, msg: &'a str) -> &'a str {};
    //          通過(guò)這種方式, 不論返回的是status還是msg都是屬于 'a 生命周期,
    //          這種表達(dá)方式滿足兩種情況, 1. 他們的生命周期長(zhǎng)短一致, 2. 返回值的類型與指定值的類型一致.
}


fn fix_error_example_that_compile_not_fill_lifetime() {
    fn print<'a>(status: &'a str, msg: &'a str) -> &'a str {
        if status == "200" {
            println!("{}: {}", status, msg);
            msg
        } else {
            println!("{}: {}", status, msg);
            status
        }
    }

    print("200", "ok!");
    print("404", "page not found!");
}


fn main() {
    multi_reference_parameters_and_return_value_is_not_reference_type();
    only_one_reference_parameter_and_return_value_type_is_reference_too();
    lifetime_on_method();
    // error_example_that_compile_not_fill_lifetime();
    fix_error_example_that_compile_not_fill_lifetime();
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唾那,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子癌淮,更是在濱河造成了極大的恐慌辱挥,老刑警劉巖罩旋,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匠题,死亡現(xiàn)場(chǎng)離奇詭異拯坟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)韭山,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門郁季,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冷溃,“玉大人,你說(shuō)我怎么就攤上這事梦裂∷普恚” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵年柠,是天一觀的道長(zhǎng)凿歼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)彪杉,這世上最難降的妖魔是什么毅往? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮派近,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洁桌。我一直安慰自己渴丸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布另凌。 她就那樣靜靜地躺著谱轨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吠谢。 梳的紋絲不亂的頭發(fā)上土童,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音工坊,去河邊找鬼献汗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛王污,可吹牛的內(nèi)容都是我干的罢吃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼昭齐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尿招!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起阱驾,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤就谜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后里覆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丧荐,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年租谈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了篮奄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捆愁。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窟却,靈堂內(nèi)的尸體忽然破棺而出昼丑,到底是詐尸還是另有隱情,我是刑警寧澤夸赫,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布菩帝,位于F島的核電站,受9級(jí)特大地震影響茬腿,放射性物質(zhì)發(fā)生泄漏呼奢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一切平、第九天 我趴在偏房一處隱蔽的房頂上張望握础。 院中可真熱鬧,春花似錦悴品、人聲如沸禀综。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)定枷。三九已至,卻和暖如春届氢,著一層夾襖步出監(jiān)牢的瞬間欠窒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工退子, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岖妄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓絮供,卻偏偏與公主長(zhǎng)得像衣吠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壤靶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容