Rust太難?那是你沒看到這套Rust語言語言學習總結(下)(rust語言難度)
2.6?原生類型
Rust內置的原生類型?(primitive types)?有以下幾類:
布爾類型:有兩個值true和false。
字符類型:表示單個Unicode字符,存儲為4個字節。
數值類型:分為有符號整數?(i8, i16, i32, i64, isize)、?無符號整數?(u8, u16, u32, u64, usize)?以及浮點數?(f32, f64)。
字符串類型:最底層的是不定長類型str,更常用的是字符串切片&str和堆分配字符串String,?其中字符串切片是靜態分配的,有固定的大小,并且不可變,而堆分配字符串是可變的。
數組:具有固定大小,并且元素都是同種類型,可表示為[T; N]。
切片:引用一個數組的部分數據并且不需要拷貝,可表示為&[T]。
元組:具有固定大小的有序列表,每個元素都有自己的類型,通過解構或者索引來獲得每個元素的值。
指針:最底層的是裸指針const T和mut T,但解引用它們是不安全的,必須放到unsafe塊里。
函數:具有函數類型的變量實質上是一個函數指針。
元類型:即(),其唯一的值也是()。
2.7?函數
2.7.1?函數參數
當函數參數按值傳遞時,會轉移所有權或者執行復制(Copy)語義。
當函數參數按引用傳遞時,所有權不會發生變化,但是需要有生命周期參數(符合規則時不需要顯示的標明)。
2.7.2?函數參數模式匹配
ref?:使用模式匹配來獲取參數的不可變引用。
ref mut?:使用模式匹配來獲取參數的可變引用。
除了ref和ref mut,函數參數也可以使用通配符來忽略參數。
具體可見《Rust編程之道》的第165頁。
2.7.3?泛型函數
函數參數并未指定具體的類型,而是用了泛型T,對T只有一個Mult trait限定,即只有實現了Mul的類型才可以作為參數,從而保證了類型安全。
泛型函數并未指定具體類型,而是靠編譯器來進行自動推斷的。如果使用的都是基本原生類型,編譯器推斷起來比較簡單。如果編譯器無法自動推斷,就需要顯式的指定函數調用的類型。
2.7.4?方法和函數
方法代表某個實例對象的行為,函數只是一段簡單的代碼,它可以通過名字來進行調用。方法也是通過名字來進行調用,但它必須關聯一個方法接受者。
2.7.5?高階函數
高階函數是指以函數作為參數或返回值的函數,它是函數式編程語言最基礎的特性。
具體可見《Rust編程之道》的第168頁。
2.8?閉包Closure
閉包通常是指詞法閉包,是一個持有外部環境變量的函數。
外部環境是指閉包定義時所在的詞法作用域。
外部環境變量,在函數式編程范式中也被稱為自由變量,是指并不是在閉包內定義的變量。
將自由變量和自身綁定的函數就是閉包。
閉包的大小在編譯期是未知的。
2.8.1?閉包的基本語法
閉包由管道符(兩個對稱的豎線)和花括號(或圓括號)組成。
管道符里是閉包函數的參數,可以向普通函數參數那樣在冒號后添加類型標注,也可以省略。例如:let add = |a, b| -> i32 { a + b };
花括號里包含的是閉包函數執行體,花括號和返回值也可以省略。
例如:let add = |a, b| a + b;
當閉包函數沒有參數只有捕獲的自由變量時,管道符里的參數也可以省略。
例如:?let add = || a + b;
2.8.2?閉包的實現
閉包是一種語法糖。閉包不屬于Rust語言提供的基本語法要素,而是在基本語法功能之上又提供的一層方便開發者編程的語法。
閉包和普通函數的差別就是閉包可以捕獲環境中的自由變量。
閉包可以作為函數參數,這一點直接提升了Rust語言的抽象表達能力。當它作為函數參數傳遞時,可以被用作泛型的trait限定,也可以直接作為trait對象來使用。
閉包無法直接作為函數的返回值,如果要把閉包作為返回值,必須使用trait對象。
2.8.3?閉包與所有權
閉包表達式會由編譯器自動翻譯為結構體實例,并為其實現Fn、FnMut、FnOnce三個trait中的一個。
FnOnce:會轉移方法接收者的所有權。沒有改變環境的能力,只能調用一次。
FnMut:會對方法接收者進行可變借用。有改變環境的能力,可以多次調用。
Fn:會對方法接收者進行不可變借用。沒有改變環境的能力,可以多次調用。
如果要實現Fn,就必須實現FnMut和FnOnce;
如果要實現FnMut,就必須實現FnOnce;
如果要實現FnOnce,就不需要實現FnMut和Fn。
2.8.3.1?捕獲環境變量的方式
對于復制語義類型,以不可變引用(&T)來進行捕獲。
對于移動語義類型,執行移動語義,轉移所有權來進行捕獲。
對于可變綁定,并且在閉包中包含對其進行修改的操作,則以可變引用(&mut T)來進行捕獲。
具體可見《Rust編程之道》的第178頁。
Rust使用move關鍵字來強制讓閉包所定義環境中的自由變量轉移到閉包中。
2.8.3.2?規則總結
如果閉包中沒有捕獲任何環境變量,則默認自動實現Fn。
如果閉包中捕獲了復制語義類型的環境變量,則:
如果不需要修改環境變量,無論是否使用move關鍵字,均會自動實現Fn。
如果需要修改環境變量,則自動實現FnMut。
如果閉包中捕獲了移動語義類型的環境變量,則:
如果不需要修改環境變量,而且沒有使用move關鍵字,則會自動實現FnOnce。
如果不需要修改環境變量,而且使用move關鍵字,則會自動實現Fn。
如果需要修改環境變量,則自動實現FnMut。
l??FnMut的閉包在使用move關鍵字時,如果捕獲變量是復制語義類型的,則閉包會自動實現Copy/Clone。如果捕獲變量是移動語義類型的,則閉包不會自動實現Copy/Clone。
2.9?迭代器
Rust使用的是外部迭代器,也就是for循環。外部迭代器:外部可以控制整個遍歷進程。
Rust中使用了trait來抽象迭代器模式。Iterator trait是Rust中對迭代器模式的抽象接口。
迭代器主要包含:
next方法:迭代其內部元素
關聯類型Item
size_hint方法:返回類型是一個元組,該元組表示迭代器剩余長度的邊界信息。
示例:
let iterator = iter.into_iter();
let size_lin = iterator.size_hint();
let mut counter = Counter { count: 0};
counter.next();
Iter類型迭代器,next方法返回的是Option<&[T]>或Option<&mut [T]>類型的值。for循環會自動調用迭代器的next方法。for循環中的循環變量則是通過模式匹配,從next返回的Option<&[T]>或Option<&mut [T]>類型中獲取&[T]或&mut [T]類型的值。
Iter類型迭代器在for循環中產生的循環變量為引用。
IntoIter類型的迭代器的next方法返回的是Option
示例:
let v = vec![1, 2, 3];
for i in v {
…
}
為了確保size_hint方法可以獲得迭代器長度的準確信息,Rust引入了兩個trait,他們是Iterator的子trait,均被定義在std::iter模塊中。
ExactSizeIterator?:提供了兩個額外的方法len和is_empty。
TrustedLen?:像一個標簽trait,只要實現了TrustLen的迭代器,其size_hint獲取的長度信息均是可信的。完全避免了容器的容量檢查,提升了性能。
2.9.1 IntoIterator trait
如果想要迭代某個集合容器中的元素,必須將其轉換為迭代器才可以使用。
Rust提供了FromIterator和IntoIterator兩個trait,他們互為反操作。
FromIterator?:可以從迭代器轉換為指定類型。
IntoIterator?:可以從指定類型轉換為迭代器。
Intoiter可以使用into_iter之類的方法來獲取一個迭代器。into_iter的參數時self,代表該方法會轉移方法接收者的所有權。而還有其他兩個迭代器不用轉移所有權。具體的如下所示:
Intoiter?:轉移所有權,對應self
Iter?:獲取不可變借用,對應&self
IterMut?:獲得可變借用,對應&mut slef
2.9.2?哪些實現了Iterator的類型?
只有實現了Iterator的類型才能作為迭代器。
實現了IntoIterator的集合容器可以通過into_iter方法來轉換為迭代器。
實現了IntoIterator的集合容器有:
Vec
&’a [T]
&’a mut [T]? =>?沒有為[T]類型實現IntoIterator
2.9.3?迭代器適配器
通過適配器模式可以將一個接口轉換成所需要的另一個接口。適配器模式能夠使得接口不兼容的類型在一起工作。
適配器也叫包裝器(Wrapper)。
迭代器適配器,都定義在std::iter模塊中:
Map?:通過對原始迭代器中的每個元素調用指定閉包來產生一個新的迭代器。
lChain?:通過連接兩個迭代器來創建一個新的迭代器。
Cloned?:通過拷貝原始迭代器中全部元素來創建新的迭代器。
Cycle?:創建一個永遠循環迭代的迭代器,當迭代完畢后,再返回第一個元素開始迭代。
Enumerate?:創建一個包含計數的迭代器,它返回一個元組(i,val),其中i是usize類型,為迭代的當前索引,val是迭代器返回的值。
Filter?:創建一個機遇謂詞判斷式過濾元素的迭代器。
FlatMap?:創建一個類似Map的結構的迭代器,但是其中不會包含任何嵌套。
FilterMap?:相當于Filter和Map兩個迭代器一次使用后的效果。
Fuse?:創建一個可以快速遍歷的迭代器。在遍歷迭代器時,只要返回過一次None,那么之后所有的遍歷結果都為None。該迭代器適配器可以用于優化。
Rev?:創建一個可以反向遍歷的迭代器。
具體可見《Rust編程之道》的第202頁。
Rust可以自定義迭代器適配器,具體的見《Rust編程之道》的第211頁。
2.10?消費器
迭代器不會自動發生遍歷行為,需要調用next方法去消費其中的數據。最直接消費迭代器數據的方法就是使用for循環。
Rust提供了for循環之外的用于消費迭代器內數據的方法,叫做消費器(Consumer)。
Rust標準庫std::iter::Iterator中常用的消費器:
l??any?:可以查找容器中是否存在滿足條件的元素。
l??fold?:該方法接收兩個參數,第一個為初始值,第二個為帶有兩個參數的閉包。其中閉包的第一個參數被稱為累加器,它會將閉包每次迭代執行的結果進行累計,并最終作為fold方法的返回值。
collect?:專門用來將迭代器轉換為指定的集合類型。
all
for_each
position
2.11?鎖
RwLock讀寫鎖:是多讀單寫鎖,也叫共享獨占鎖。它允許多個線程讀,單個線程寫。但是在寫的時候,只能有一個線程占有寫鎖;而在讀的時候,允許任意線程獲取讀鎖。讀鎖和寫鎖不能被同時獲取。
Mutex互斥鎖:只允許單個線程讀和寫。
三、?Rust屬性
#[lang = “drop”]?:?將drop標記為語言項
#[derive(Debug)]?:
#[derive(Copy, Clone)]?:
#[derive(Debug,Copy,Clone)]?:
#[lang = “owned_box”]?:?Box
#[lang = “fn/fn_mut/fn_once”]?:表示其屬于語言項,分別以fn、fn_mut、fn_once名稱來查找這三個trait。
fn_once:會轉移方法接收者的所有權
fn_mut:會對方法接收者進行可變借用
fn:會對方法接收者進行不可變借用
#[lang = “rust_pareen_sugar”]?:表示對括號調用語法的特殊處理。
#[must_use=”iterator adaptors are lazy ……”]?:用來發出警告,提示開發者迭代器適配器是惰性的。
四、內存管理
4.1?內存回收
drop-flag:在函數調用棧中為離開作用域的變量自動插入布爾標記,標注是否調用析構函數,這樣,在運行時就可以根據編譯期做的標記來調用析構函數。
實現了Copy的類型,是沒有析構函數的。因為實現了Copy的類型會復制,其生命周期不受析構函數的影響。
需要繼續深入理解第4章并總結,待后續補充。
五、unicode
Unicode字符集相當于一張表,每個字符對應一個非負整數,該數字稱為碼點(Code Point)。
這些碼點也分為不同的類型:
標量值
代理對碼點
非字符碼點
l??保留碼點
l??私有碼點
標量值是指實際存在對應字符的碼位,其范圍是0x0000~0xD7FF和0xE000~0x10FFFF兩段。
Unicode字符集的每個字符占4個字節,使用的存儲方式是:碼元(Code Unit)組成的序列。
碼元是指用于處理和交換編碼文本的最小比特組合。
Unicode字符編碼表:
UTF-8????? =>?1字節碼元
UTF-16??? =>?2字節碼元
UTF-32??? =>?4字節碼元
Rust的源碼文件.rs的默認文本編碼格式是UTF-8。
六、Rust附錄
字符串對象常用的方法
方法
原型
說明
new()
pub const fn new() -> String
創建一個新的字符串對象
to_string()
fn to_string(&self) -> String
將字符串字面量轉換為字符串對象
replace()
pub fn replace<'a, P>(&'a self, from: P, to: &str) -> String
搜索指定模式并替換
as_str()
pub fn as_str(&self) -> &str
將字符串對象轉換為字符串字面量
push()
pub fn push(&mut self, ch: char)
再字符串末尾追加字符
push_str()
pub fn push_str(&mut self, string: &str)
再字符串末尾追加字符串
len()
pub fn len(&self) -> usize
返回字符串的字節長度
trim()
pub fn trim(&self) -> &str
去除字符串首尾的空白符
split_whitespace()
pub fn split_whitespace(&self) -> SplitWhitespace
根據空白符分割字符串并返回分割后的迭代器
split()
pub fn split<'a, P>(&'a self, pat: P) -> Split<'a, P>
根據指定模式分割字符串并返回分割后的迭代器。模式?P?可以是字符串字面量或字符或一個返回分割符的閉包
chars()
pub fn chars(&self) -> Chars
返回字符串所有字符組成的迭代器
Rust
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。