日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

詳解Rust編程中的生命周期

來源: 責(zé)編: 時(shí)間:2024-01-09 08:52:55 336觀看
導(dǎo)讀1.摘要生命周期在Rust編程中是一個(gè)重要概念, 它能確保引用像預(yù)期的那樣一直有效。在Rust語言中, 每一個(gè)引用都有其生命周期, 通俗講就是每個(gè)引用在程序執(zhí)行的過程中都有其自身的作用域, 一旦離開其作用域, 其生命周期

1.摘要

生命周期在Rust編程中是一個(gè)重要概念, 它能確保引用像預(yù)期的那樣一直有效。在Rust語言中, 每一個(gè)引用都有其生命周期, 通俗講就是每個(gè)引用在程序執(zhí)行的過程中都有其自身的作用域, 一旦離開其作用域, 其生命周期也宣告結(jié)束, 值不再有效。eEt28資訊網(wǎng)——每日最新資訊28at.com

幸運(yùn)的是, 在絕大多數(shù)時(shí)間里, 生命周期是隱含且可以進(jìn)行推斷的, 類似于當(dāng)有多種可能的類型時(shí)必須注明類型, 正因?yàn)槿绱? 所以Rust需要使用者使用泛型生命周期參數(shù)來注明它們的關(guān)系, 從而確保程序運(yùn)行時(shí)實(shí)際使用的引用絕對(duì)有效。eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

2.懸垂引用問題

懸垂引用會(huì)導(dǎo)致Rust編程中出現(xiàn)一些潛在的安全問題, 例如: 程序在無意之中引用了非預(yù)期引用的數(shù)據(jù), 而這種現(xiàn)象在沒有任何約束的情況下很容易出現(xiàn)。Rust編程中引入生命周期的主要原因就是避免編程過程中出現(xiàn)的懸垂引用問題。eEt28資訊網(wǎng)——每日最新資訊28at.com

下面看一個(gè)代碼示例:eEt28資訊網(wǎng)——每日最新資訊28at.com

fn main() {   let num;   {      let count = 5;      num = &count;   }   println!("num: {}", num);}

首先定義了一個(gè)變量num, 下面的花括號(hào)表示進(jìn)入到一個(gè)作用域, 在該作用域中, 定義了一個(gè)變量count,并賦值為5, 在這個(gè)內(nèi)部作用域中,&count表示一個(gè)對(duì)變量count的引用, 然后將其賦給變量num, 在作用域的外部, 調(diào)用println打印出num的值。eEt28資訊網(wǎng)——每日最新資訊28at.com

先嘗試編譯一下這段代碼試試:eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

Rust編譯器報(bào)錯(cuò)的地方指向代碼: num = &count, 并報(bào)了一個(gè)錯(cuò)誤:"borrowed value does not live long enough", 意思是&count的值并沒有存在足夠久, 并很貼心的用藍(lán)色字告訴我們作用域的范圍界定。那么有一個(gè)問題, Rust編譯器是以什么機(jī)制來判定作用域使用的合法性呢?eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

3.Rust檢查機(jī)制

在Rust編譯器中, 有一個(gè)被稱為借用檢查器的機(jī)制, 它的主要工作原理是通過比較作用域來確保代碼中所有的借用都是有效的, 看一下下面的代碼標(biāo)識(shí):eEt28資訊網(wǎng)——每日最新資訊28at.com

fn main() {   let num; ------------------------- num_s   { |      let count = 5; ------ count_s |      num = &count; --------- |   } |   println!("num: {}", num);------------}

這里將上面代碼中的兩個(gè)關(guān)鍵變量num和count分別引入一個(gè)各自代表其生命周期的標(biāo)識(shí):num_s和count_s。很明顯可以看到, num變量的起點(diǎn)在作用域上面, 終點(diǎn)在作用域下面,。而count_s的生命周期起點(diǎn)在進(jìn)入第一個(gè)花括號(hào)后面, 終點(diǎn)在第二個(gè)花括號(hào)前面, 也就是說, num變量的生命周期num_s包含了count_s的生命周期, 所以Rust編譯器利用借用檢查器比較兩個(gè)變量的生命周期大小, 很容易推斷出num的生命周期明顯要長(zhǎng)。eEt28資訊網(wǎng)——每日最新資訊28at.com

上面的代碼被Rust編譯器拒絕編譯, 正是因?yàn)榻栌脵z查器首先發(fā)現(xiàn) num_s的生命周期比count_s要長(zhǎng), 而num = &count這句代碼, 被引用的對(duì)象&count比引用者num存在的時(shí)間更短, 因此產(chǎn)生了懸垂引用。eEt28資訊網(wǎng)——每日最新資訊28at.com

那么解決該問題的方式也比較簡(jiǎn)單, 只要被引用對(duì)象和引用者處于同一作用域即可解決, 如下代碼:eEt28資訊網(wǎng)——每日最新資訊28at.com

方式一:eEt28資訊網(wǎng)——每日最新資訊28at.com

fn main() {   let count = 5;   let num = &count;   println!("num: {}", num);}

方式二:eEt28資訊網(wǎng)——每日最新資訊28at.com

fn main() {    let num;    {        let count = 5;        num = &count;        println!("num: {}", num);    }}

eEt28資訊網(wǎng)——每日最新資訊28at.com

4.泛型生命周期

下面有一段代碼, 主要完成了兩個(gè)字符串的長(zhǎng)度比較功能, 其中compare函數(shù)負(fù)責(zé)完成兩個(gè)字符串的長(zhǎng)度比較并返回長(zhǎng)度最長(zhǎng)的字符串的eEt28資訊網(wǎng)——每日最新資訊28at.com

切片。代碼如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

fn compare(a: &str, b: &str) -> &str {    if a.len() > b.len() {       a    } else {       b    }}fn main() {   let sample1 = String::from("sample for suntiger");   let sample2 = "suntiger";      let c_result = compare(sample1.as_str(), sample2);   println!("最長(zhǎng)的字符串是 {}", c_result);}

這段代碼編譯時(shí),Rust編譯器的返回如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

上面的錯(cuò)誤提示分為三個(gè)部分: compare函數(shù)的兩個(gè)參數(shù)以及返回值存在生命周期問題。首先, Rust編譯器并不清楚將要返回的引用&str到底是指向參數(shù)a還是參數(shù)b, 其實(shí)作為程序員自己也是不知道的, 因?yàn)橹挥性谶\(yùn)行時(shí)通過比較兩個(gè)參數(shù)的長(zhǎng)度大小后才知道哪個(gè)參數(shù)切片的字符串內(nèi)容更長(zhǎng)。eEt28資訊網(wǎng)——每日最新資訊28at.com

因此, 根據(jù)Rust編譯器的綠色標(biāo)記提示, 在編寫compare函數(shù)時(shí), 必須增加泛型生命周期參數(shù)來定義引用間的關(guān)系以便Rust的檢查機(jī)制能夠正確分析。eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

5.生命周期注解

在上面的編譯器返回提示中, 綠色的部分: <'a>、&'a被稱為生命周期注解, 這個(gè)也是Rust語言獨(dú)特的語法, 看起來比較奇葩和抽象, 那么Rust如何去定義這個(gè)注解呢, 以下是簡(jiǎn)單的語法:eEt28資訊網(wǎng)——每日最新資訊28at.com

&str // 稱為引用&'a str // 稱為帶有顯式生命周期的引用&'a mut str // 稱為帶有顯式生命周期的可變引用

生命周期注解的一個(gè)重要作用就是告訴Rust編譯器在多個(gè)引用的泛型生命周期參數(shù)存在期間它們?nèi)绾蜗嗷ヂ?lián)系。eEt28資訊網(wǎng)——每日最新資訊28at.com

嘗試將compare函數(shù)代碼修改如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

fn compare<'a>(a: &'a str, b: &'a str) -> &'a str {    if a.len() > b.len() {       a    } else {       b    }}

再次嘗試編譯, Rust編譯器返回如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

這次返回了正確的結(jié)果, 當(dāng)在函數(shù)中使用生命周期注解時(shí), 這些注解只存在于函數(shù)簽名中, 而不存在于函數(shù)體的任何代碼中, 當(dāng)在實(shí)際應(yīng)用過程中, 參數(shù)的引用傳給compare函數(shù)時(shí), 被'a取代的具體生命周期是參數(shù)a的作用域與參數(shù)b的作用域重疊的那一部分, 換句話說就是兩個(gè)參數(shù)中生命周期較小的那一個(gè)。eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

6.結(jié)構(gòu)體生命周期注解

eEt28資訊網(wǎng)——每日最新資訊28at.com

在定義結(jié)構(gòu)體時(shí), 也要在相應(yīng)的地方加上生命周期注解, 結(jié)構(gòu)體定義如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

struct PersonInfo<'a> {    name: &'a str,}

在該結(jié)構(gòu)體中定義了一個(gè)name的字段, 其中存放了一個(gè)字符串切片, 為了能夠在結(jié)構(gòu)體定義中使用生命周期參數(shù), 必須在結(jié)構(gòu)體名稱后面的括號(hào)中聲明泛型生命周期參數(shù)。eEt28資訊網(wǎng)——每日最新資訊28at.com

接下來需要在main函數(shù)中創(chuàng)建一個(gè)結(jié)構(gòu)體實(shí)例, 將一個(gè)字符串切片內(nèi)容傳給結(jié)構(gòu)體參數(shù), 代碼如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

fn main() {    let sayinfo = String::from("今天天氣不錯(cuò)#挺風(fēng)和日麗的...");    let headerinfo = sayinfo.split('#').next().expect("找不到分隔符'#'");    let pi = PersonInfo {        name: headerinfo,    };    println!("分割name內(nèi)容為: {}", pi.name);}

在上面的代碼中, 對(duì)變量sayinfo中的內(nèi)容作了字符串分割, 如果找到符號(hào)#,則取前面的內(nèi)容,然后將該部分內(nèi)容存到結(jié)構(gòu)體字段中。eEt28資訊網(wǎng)——每日最新資訊28at.com

編譯結(jié)果如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

因?yàn)樽兞縮ayinfo在結(jié)構(gòu)體PersonInfo之前創(chuàng)建, 且結(jié)構(gòu)體離開作用域之后,變量sayinfo仍然不會(huì)離開作用域, 因此PersonInfo實(shí)例中的引用一直都是有效的, 并不會(huì)出問題。eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

7.靜態(tài)生命周期

eEt28資訊網(wǎng)——每日最新資訊28at.com

靜態(tài)生命周期和靜態(tài)變量一樣, 都有一個(gè)關(guān)鍵字: static, 例子代碼如下:eEt28資訊網(wǎng)——每日最新資訊28at.com

let sample: &'static str = "我是一個(gè)靜態(tài)周期的例子.";

現(xiàn)在變量sample的生命周期會(huì)一直持續(xù), 在整個(gè)程序中都是有效的, 盡管靜態(tài)生命周期會(huì)避免編碼過程中的很多編譯器檢查錯(cuò)誤, 但是一旦在編碼過程中出現(xiàn)懸垂引用的錯(cuò)誤編碼時(shí), 更正確的做法應(yīng)該是想辦法解決懸垂引用的問題,而不是靠靜態(tài)生命周期避開錯(cuò)誤。eEt28資訊網(wǎng)——每日最新資訊28at.com

eEt28資訊網(wǎng)——每日最新資訊28at.com

8.總結(jié)

在本篇文章中我們探索了生命周期在Rust常見場(chǎng)景中的各種應(yīng)用, 但在復(fù)雜的業(yè)務(wù)場(chǎng)景中, 可能還會(huì)遇到其它錯(cuò)誤, 這時(shí)候依靠Rust編譯器強(qiáng)大的提示功能應(yīng)該能夠準(zhǔn)確找到出現(xiàn)問題的地方, 在這個(gè)過程中解決問題, 除了加深印象, 還能起到舉一反三的作用。eEt28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-58978-0.html詳解Rust編程中的生命周期

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 當(dāng)別人因?yàn)镽eact、Vue吵起來時(shí),我們應(yīng)該做什么

下一篇: Python基礎(chǔ):格式化輸出

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 靖远县| 乡宁县| 明星| 穆棱市| 崇明县| 衡东县| 沂水县| 济阳县| 云浮市| 安陆市| 巴塘县| 靖安县| 奉贤区| 万荣县| 平阳县| 凯里市| 衡山县| 石城县| 平陆县| 雅安市| 石阡县| 丹凤县| 西峡县| 封丘县| 南澳县| 垦利县| 临武县| 平果县| 宝丰县| 汕尾市| 隆林| 伊宁市| 锡林郭勒盟| 佛山市| 上犹县| 运城市| 七台河市| 五大连池市| 深泽县| 博客| 抚州市|