系列文章目錄
【rust】| 00——開發(fā)環(huán)境搭建
【rust】| 01——編譯并運行第一個rust程序
【rust】| 02——語法基礎(chǔ) | 變量(不可變?)和常量
【rust】| 03——語法基礎(chǔ) | 數(shù)據(jù)類型
【rust】| 04——語法基礎(chǔ) | 函數(shù)
【rust】| 05——語法基礎(chǔ) | 流程控制
【rust】| 06——語言特性 | 所有權(quán)
1. 所有權(quán)的概念
?所有權(quán)是Rust語言中一個關(guān)鍵的特性。它是一種內(nèi)存管理規(guī)則(機(jī)制)。它通過這個規(guī)則(即所有權(quán)系統(tǒng))結(jié)合編譯器對代碼進(jìn)行檢查 從而確保內(nèi)存安全。
?在其他語言如C/C++ 等 都有自己的內(nèi)存管理方式。C/C++需要我們顯式(手動)處理所用的內(nèi)存(申請、釋放) 如果處理不當(dāng)會造成很嚴(yán)重的內(nèi)存安全問題。而Rust中這一特性很好的可以幫我們確保內(nèi)存安全性。
2. 所有權(quán)的規(guī)則
1、每個值都對應(yīng)一個變量 owner
2、一個值只能有一個 owner
3、有作用域,當(dāng)owner超出作用域 值會被銷毀 (這個變量有生命周期 在作用域內(nèi))
3. 變量的作用域
Rust中變量的作用域和其他語言類型。比如函數(shù)體內(nèi)的 變量(局部變量) 它的作用域在 函數(shù)大括號之間 生命周期也是這么短。
可以看到 超過范圍銷毀了。 對應(yīng)所有權(quán)規(guī)則的最后一條。owner 就是這個值藏在暗處的變量名。 它超過變量作用域會消失。Rust內(nèi)部在超出后 會掉清理函數(shù) drop
清理變量占用的內(nèi)存。
4. 所有權(quán)的移動/克隆
4.1 移動
Rust中的移動 類似淺拷貝 但有細(xì)節(jié)之處。
我們通過代碼例子去理解
1、變量賦值操作
分析:
? 1、整型變量賦值 變量a 復(fù)制到了 變量b
? 2、字符串賦值 變量s1 復(fù)制到了 變量s2
? 我們可以看到 兩種不同的類型 操作幾乎是一樣的。 整型它只是一個數(shù)字 再怎么復(fù)制占用的大小就那么多 無關(guān)緊要??墒钱?dāng)是一個很大的字符串 復(fù)制給另一個變量 那所占用的大小(很大*2) 這樣的操作 太占用大小 咋的一個字符串準(zhǔn)備要我命啊。是不是和其他語言復(fù)制操作很類似。
? 但是在 Rust中 復(fù)制的操作 還是有細(xì)微差別的 我們深入了解下rust下 具體復(fù)制的具體過程
細(xì)看 字符串變量的定義及復(fù)制到其他變量的過程
可以看到 字符串變量的內(nèi)容 hello 存儲在堆上 而 定義的變量 S1 只保存了 指向堆上內(nèi)容的指針、長度和容量這三個 這些內(nèi)容存儲在棧上。并沒有將 字符串內(nèi)容也保存。
下面我們看 S1內(nèi)容復(fù)制給S2 是怎樣的
可以看到 S1 復(fù)制到 S2 也只是復(fù)制了 指針、長度、容量三件套。不重復(fù)復(fù)制堆上內(nèi)容。這樣的情況下S1 S2是不是 占用棧大小很少。
如果S1 S2把數(shù)據(jù)一起保存呢
可以看到 全保存過來 每個變量 都這樣完全復(fù)制 那棧吃不消。當(dāng)內(nèi)容很大時 是不是 一個賦值操作直接給 棧空間 用完 干廢掉啦。
通過上面圖我們可以看到 rust中 變量保存了指向內(nèi)容的指針等。 S1 和S2 中的指針都指向了 數(shù)據(jù)內(nèi)容。我們知道所有權(quán)規(guī)則之一 變量超出作用域 會沒了。那么當(dāng)S1和S2 超出作用域 會嘗試釋放 因為它兩指向一個地址那么 兩次釋放是不是會出大問題呢。也稱為 雙重釋放錯誤。
當(dāng)然 rust中也會想到這種錯誤 所以它會避免啦。
在Rust中 執(zhí)行完 S2=S1這樣的操作 S1已經(jīng)變得無效啦 所以不會再存在上面雙重釋放的隱患了。
其實 Rust中S2 = S1 的操作類似淺拷貝 只拷貝了指針長度容量。但是rust 中超出范圍 讓其消失的規(guī)則 即S1 無效啦的操作 我們把這樣稱為 移動。
4.2 克隆 clone
Rust中 我們把類似 深拷貝(把數(shù)據(jù)內(nèi)容一起復(fù)制)的操作
稱為克隆 clone。
4.3 copy
前面學(xué)習(xí)完 移動和克隆 我們理解到 在Rust中 通過變量給變量賦值的操作 如果直接賦值 S2 = S1 這種 類似于淺拷貝 而且S1會消失 沒有拷貝在堆上的內(nèi)容 而 通過克隆 s2=s1.clone() 這種 類似深拷貝的操作 這樣S1還活著。 下面我們通過例子理解COPY
為什么x 還能用? 因為X是整型 編譯器編譯時 知道它的大小 將內(nèi)容全部存儲在棧中。也可以說整型具有copy特性 所以才會存在棧上。字符串型 大小我們不確定因為不知道后面會不會 改變。 在這種情況下 深淺拷貝(克隆)沒區(qū)別。
具有copy特性的類型
- 所以整型
- 布爾類型
- 所以浮點型
- 字符型 char
- 元組(元素類型為以上幾種)
5. 所有權(quán)的轉(zhuǎn)移
函數(shù)和返回值 都可以轉(zhuǎn)移屬性
5.1 函數(shù)轉(zhuǎn)移
通過函數(shù)入?yún)?將變量移動/復(fù)制 和變量移動/復(fù)制一樣的
通過例子學(xué)習(xí)
通過這個可以看到 和變量是一樣的
5.2 返回值轉(zhuǎn)移
通過返回值 轉(zhuǎn)移
6. 引用和借用
有些場景我們只需要使用值 而且會多次使用 一個變量本身具有所有權(quán) 多次使用需要移動來移動去 好麻煩 有沒有辦法不要所有權(quán) 那就是通過引用的方式。
6.1 引用
引用: 使用值而不轉(zhuǎn)移(獲取)所有權(quán)
引用沒有所有權(quán)
引用通過地址來訪問存儲在該地址的數(shù)據(jù)
我們可以看到上面 函數(shù)定義入?yún)?s: &sring 它的含義 我們創(chuàng)建了一個引用 來接收傳入的實參引用 也稱為 借用
6.2 借用
借用 是創(chuàng)建引用的動作
借用是 不能修改引用的值
借用 顧名思義 我借了別人東西 我要原模原樣還給人家 不能說 搞壞了還吧
上demo
可以看到 引用 和 默認(rèn)情況下的變量 一樣是不可變的
6.3 可變引用
引用默認(rèn)情況下 不可修改內(nèi)容 和默認(rèn)變量一樣
上面代碼因為我們定義了不可變的變量等 那我們給他給加上可變的標(biāo)志 是不是就可以變啦 是的
可以看到 定義變量 函數(shù)入?yún)⒌?都修改為 可變的 少一個都不行 否者會報錯 既然要該那么都得是可變屬性哦
可變引用的約束
1、一個變量只能有一個可變引用
防止多個引用同時對一個值 修改
6.4 空引用
類似空指針。
在rust中 編譯器會保證不會存在空引用。
編譯器檢測過程
但我們又想用 函數(shù)內(nèi)局部變量怎么辦
前面我們學(xué)習(xí)了 返回值可以轉(zhuǎn)移所有權(quán) 那么我們返回 變量是不是就可以了
7. 切片
切片也是一種引用,切片沒有所有權(quán)。
切片:對一個集合(元組 字符串) 引用其部分連續(xù)元素的操作注: 切片不能對整個切 只能連續(xù)的某部分 是有范圍的
7.1 字符串切片
我們看看切片數(shù)據(jù)的內(nèi)部存儲結(jié)構(gòu)是怎樣的
可以看到切片只存儲了 起始位置的指針 和切的長度
還有一種字符串類型 &str 它指向二進(jìn)制文件 這個字符串不可變
let s=“awdada”; // s是 &str類型
7.2 其他切片
和字符串切片類似 只是切的對象換了 可以切好多
比如 切數(shù)組 引用數(shù)組中一部分元素
7.3 切片的范圍
我們通過前面知道切片是如何創(chuàng)建
知道了 [ ] 方括號之間需要填切片的范圍
那么當(dāng)我們想切片的起始位置從0開始 除了 [0…x] 還有其他的表達(dá)方式
1、切片索引從0開始 的表達(dá)方式
同樣的 結(jié)尾位置 也可以 用省略 表達(dá)
2、切片索引 到末尾 的表達(dá)方式
3、表示整個 同理 省略起始和結(jié)尾值 [ . . ]文章來源:http://www.zghlxwxcb.cn/news/detail-443607.html
7.4 切片做函數(shù)參數(shù)
文章來源地址http://www.zghlxwxcb.cn/news/detail-443607.html
到了這里,關(guān)于【rust】| 06——語言特性 | 所有權(quán)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!