鎮(zhèn)江百度競價南昌seo管理
文章目錄
- 一、string
- 二、所有權
- 2.1 所有權與作用域
- 2.2 對所有權的操作
- 2.2.1 轉移
- 2.2.3 拷貝
- 2.2.3 傳遞
- 2.3 引用
- 2.3.1 借用
- 2.3.2 可變引用
一、string
之前學習過 Rust 只有幾種基礎的數(shù)據(jù)類型,但是沒有常用的字符串也就是String,今天來學習一下 String;
Rust 中 String 是標準庫的一部分,也就是 std::String , 但是這個 String 與其他語言中的 String 稍有不同,比如:
可以看到,當我想要以一種為指定字符串類型的方式定義了一字符串變量時,編譯器自動顯示出的類型是 &srr 而非 String, 而我指定了 String 類型后仍然有錯;而從編譯器給出的提示不難看出,“hello” 這樣定義得到的是一個 “&str” 類型的值而非是個字符串,那么我們先假定這是一種未知的類型,后續(xù)再處理它,先去想辦法定義出我們的字符串,打開官方文檔: https://doc.rust-lang.org/std/string/struct.String.html
可以看到官方文檔第一個示例告訴我們要像這樣創(chuàng)建字符串:
但是官方沒說為什么要這樣定義,幸好 Rust 的源碼是可以點進去的, 從 String::from 向里一步步執(zhí)行:
from 執(zhí)行的操作只有一個就是調用 to_owned 函數(shù),但是需要注意,這里傳進來的參數(shù)類型仍然是"&str"; 然后 to_owned 下一步是調用 as_bytes().to_owned() ,最后這個 to_owned() 則是調用了 to_vec ;
那么至此也就明白了,對于這一行代碼:
let hello = String::from("Hello, ");
我們傳入的 “Hello,” 這會被編譯器認為是一個字符數(shù)組,也就是一個字符串常量,即無法對其造成改變的一個對象;但是我們需要的是一個可變的字符串而非一組固定的字符,因此編譯器將這個字符數(shù)組擴展為了一個 vector , 也就變成了一個可變的字符數(shù)組,也就是我最終想要的字符串;
其實這和C++差不多,只不過C++string底層應該直接是個指針而不是個vector
這樣一來 “&str” 也就理解了,就是一個常量字符數(shù)組,所以是不可變的。在官方文檔搜一下,果然也有,并且還有個好聽的名字,字符串切片(string slice),具體參考: https://doc.rust-lang.org/std/primitive.str.html
官方文檔中還介紹了兩種類型的互轉方法:
剩下的使用就是這兩種類型自帶的一些接口了,具體請參閱官方文檔,這里不再細述;
二、所有權
2.1 所有權與作用域
很多小伙伴開始學習 Rust 是因為聽說這是一種比C++更安全的語言,所以來了解一下,那么它安全在哪里?就安全在所有權機制,不再需要開發(fā)者像C++一樣的去人工管理內存。
首先,所有程序都必須管理其運行時使用計算機內存的方式。一些語言中具有垃圾回收機制,在程序運行時有規(guī)律地尋找不再使用的內存,比如Java;另一些語言中,程序員必須親自分配和釋放內存,比如C/C++。Rust 則選擇了第三種方式:通過所有權系統(tǒng)管理內存,編譯器在編譯時會根據(jù)一系列的規(guī)則進行檢查。如果違反了任何這些規(guī)則,程序都不能編譯。在運行時,所有權系統(tǒng)的任何功能都不會減慢程序。所有權有以下規(guī)則:
* Rust 中的每一個值都有一個 所有者(owner)。
* 值在任一時刻有且只有一個所有者。
* 當所有者(變量)離開作用域,這個值將被丟棄。
舉個例子,有以下一段代碼:
fn main() {let s1 = "hello";{ let s = "hello s"; } let s2 = "hello";
}
在上面的代碼中, s 被一個括號圈住了,那么在這個括號里"hello s" 的所有者就是 s,而 s 的生命周期也只在括號范圍內,也就是 s1 出現(xiàn)時 s 未出現(xiàn), s2 出現(xiàn)時 s 已經死去。
有過C++ 經驗的小伙伴看到這肯定很熟悉,這不就是 RAII 嗎,或者說 Rust 中的每個變量都是個智能指針。
2.2 對所有權的操作
2.2.1 轉移
剛剛說到這種所有權機制與C++的 RAII 很像,變量也和智能指針很像,那么是不是就和智能指針一樣呢,測試一下:
圖上可以看到,先定義了 s1 ,然后定義 s2 ,然后將 s1 傳遞給 s2 ,此時再使用 s1 會報錯,提醒你s1 的值已經被轉移出去了, 這時 s1 就已經被清空了。因為 Rust 變量離開作用域時會回收,所以如果這里不清空,在程序結束時s1 s2都會被回收,那么一塊內存就會回收了兩次,因此 Rust 的機制中 = 操作是轉移而非拷貝。
看到這里,還是覺得是智能指針,只不過是unique_ptr,QAQ
2.2.3 拷貝
= 是轉移而不是拷貝,那么想要使用拷貝該怎么寫呢?比如字符串這樣:
調用 clone 函數(shù)就行了。
然后有一個很有意思的事情,比如:
i32 類型變量不需要使用 clone 之類的函數(shù),= 居然就是拷貝而不是轉移;
官方給出的解釋是 “像整型這樣的在編譯時已知大小的類型被整個存儲在棧上,所以拷貝其實際的值是快速的。這意味著沒有理由在創(chuàng)建變量 y 后使 x 無效?!?/strong> 恕我直言,這不就是Rust中所有用到堆的變量就用的是智能指針嗎。。。。。當然也可能是我理解不夠深,反正我目前為止的感受就是這樣。。。。
2.2.3 傳遞
之前提到過 “值在任一時刻有且只有一個所有者” ,那么如果將值傳遞給函數(shù)會怎么樣呢:
很明顯,作為參數(shù)傳遞給函數(shù)之后就失去了所有權;
但這樣會帶來一個問題,這個值如果不只一個函數(shù)再用后續(xù)怎么辦?用函數(shù)返回值返回!
但是如果參數(shù)不只有一個呢?為每個函數(shù)的返回值都定一個結構體?
這樣太麻煩了,萬幸的是 Rust 提供了 引用。
2.3 引用
2.3.1 借用
官方說明中“引用(reference)像一個指針,因為它是一個地址,我們可以由此訪問儲存于該地址的屬于其他變量的數(shù)據(jù)。 與指針不同,引用確保指向某個特定類型的有效值?!?br /> 很好理解,改一下剛才的代碼:
可以用了,修改就是函數(shù)聲明參數(shù)時加了一個&,傳參時也加了一個&;
變量 str 有效的作用域與函數(shù)參數(shù)的作用域一樣,不過當 str 停止使用時并不丟棄引用指向的數(shù)據(jù),因為 str 并沒有所有權。當函數(shù)使用引用而不是實際值作為參數(shù),無需返回值來交還所有權,因為就不曾擁有所有權。
Rust 將創(chuàng)建一個引用的行為稱為 借用(borrowing)。正如現(xiàn)實生活中,如果一個人擁有某樣東西,你可以從他那里借來。當你使用完畢,必須還回去,并不擁有它,因此借用的值無法修改。
2.3.2 可變引用
正如不可變變量與可變變量一樣,引用也可以變?yōu)榭勺円?#xff0c;加個 mut 關鍵試試:
當然,像這段代碼所寫的,想要成為可變引用的前提是自身就是可變的。
另外,由于 Rust 的三條基礎規(guī)則之“值在任一時刻有且只有一個所有者”,那么對于一個可變變量在同一個時刻也就不可以有多個引用;換個角度理解比如用一個 s1 作為 s 的可變引用后,那么 s 將不再可用,也自然不能再對一個無法使用的變量創(chuàng)建引用,如果這樣使用編譯器就會報錯: