測試
測試我不打算很詳細的寫,大家知道如何使用其實就差不多了
編寫測試模塊
一般來說我們在lib中編寫測試
cargo new test_01 --lib
這樣我們構(gòu)建了一個test的lib
在這個工程里面你看到應(yīng)該是有個lib.rs沒有main.rs的
聲明test模塊
這里并不是聲明一個mod,而是一個測試區(qū)域,在區(qū)域中可以寫很多的測試方法
我們通過#[cfg(test)]
宏來進行標注
#[cfg(test)]
mod tests {
}
編寫測試方法
測試方法和普通方法沒什么區(qū)別,主要在于標注#[test]
#[test]
fn test01() {
assert_eq!(6, 4);
}
執(zhí)行測試
我們使用cargo test
就可以啟動進行測試了,測試會將所有標注#[test]
的方法都測試一遍
測試結(jié)果檢查
我們通常使用assert檢查測試結(jié)果
- assert:斷言結(jié)果為true,否則panic
- assert_eq:斷言兩邊相等,否則panic
- assert_ne:斷言兩邊不等,否則panic
閉包
一個可以儲存在變量里的類似函數(shù)的結(jié)構(gòu)
Rust 的 閉包(closures)是可以保存在一個變量中或作為參數(shù)傳遞給其他函數(shù)的匿名函數(shù)??梢栽谝粋€地方創(chuàng)建閉包,然后在不同的上下文中執(zhí)行閉包運算。不同于函數(shù),閉包允許捕獲被定義時所在作用域中的值。我們將展示閉包的這些功能如何復用代碼和自定義行為。
定義一個閉包
如下,我們使用||{}
定義了一個閉包,很像是函數(shù)的寫法:
fn main() {
let a = || {
10
};
println!("{}",a());
}
這個閉包會返回10,但是實際a的類型是fn:fn->i32
,對于但語句來說將{}
省略也是OK的
完整寫法
|參數(shù)|->返回值{
//...
}
閉包可以捕獲環(huán)境
如下的閉包中使用到了b變量,但是b沒有傳入閉包,這就和函數(shù)有了差別,使得我們在做一些簡單的,不用復用的操作的時候可以直接使用閉包而不是定義一個函數(shù)
fn main() {
let b = 16;
let a = |x:i32| {
b * x
};
println!("{}",a(10));
}
閉包類比函數(shù)
這里給出圣經(jīng)中的例子:
fn add_one_v1 (x: u32) -> u32 { x + 1 }
let add_one_v2 = |x: u32| -> u32 { x + 1 };
let add_one_v3 = |x| { x + 1 };
let add_one_v4 = |x| x + 1 ;
閉包類型推斷
我們看這個程序,看上去沒任何問題,但是實際上會報錯,原因就是閉包類型推斷,前面我們知道閉包會自動推斷類型,所以當?shù)谝淮螆?zhí)行的時候,閉包認為返回值是String,第二次再次調(diào)用相同的閉包導致了返回值類型不一致,所以報錯:
fn main() {
let example_closure = |x| x;
let s = example_closure(String::from("hello"));
let n = example_closure(5);
}
閉包獲取所有權(quán)
閉包體不嚴格需要所有權(quán),如果希望強制閉包獲取它用到的環(huán)境中值的所有權(quán),可以在參數(shù)列表前使用 move 關(guān)鍵字
在將閉包傳遞到一個新的線程時這個技巧很有用,它可以移動數(shù)據(jù)所有權(quán)給新線程
move ||->返回值類型{
}
將被捕獲的值移出閉包和 Fn trait
閉包捕獲和處理環(huán)境中的值的方式影響閉包實現(xiàn)的 trait。Trait 是函數(shù)和結(jié)構(gòu)體指定它們能用的閉包的類型的方式。取決于閉包體如何處理值,閉包自動、漸進地實現(xiàn)一個、兩個或三個 Fn trait。
-
FnOnce
適用于能被調(diào)用一次的閉包,所有閉包都至少實現(xiàn)了這個 trait,因為所有閉包都能被調(diào)用。一個會將捕獲的值移出閉包體的閉包只實現(xiàn) FnOnce trait,這是因為它只能被調(diào)用一次。 -
FnMut
適用于不會將捕獲的值移出閉包體的閉包,但它可能會修改被捕獲的值。這類閉包可以被調(diào)用多次。 -
Fn
適用于既不將被捕獲的值移出閉包體也不修改被捕獲的值的閉包,當然也包括不從環(huán)境中捕獲值的閉包。這類閉包可以被調(diào)用多次而不改變它們的環(huán)境,這在會多次并發(fā)調(diào)用閉包的場景中十分重要。
迭代器
迭代器模式允許你對一個序列的項進行某些處理。迭代器(iterator)負責遍歷序列中的每一項和決定序列何時結(jié)束的邏輯。當使用迭代器時,我們無需重新實現(xiàn)這些邏輯。
迭代器是惰性的:調(diào)用方法使用迭代器前無效
創(chuàng)建一個迭代器
調(diào)用復合類型的iter方法即可創(chuàng)建,但此時無效
fn main() {
let arr = vec![1,2,3];
let item_iter = arr.iter();
}
應(yīng)用迭代器遍歷
以下是使用for對迭代器進行遍歷
fn main() {
let mut arr = Vec::new();
arr.push(1);
arr.push(2);
let item_iter = arr.iter();
for item in item_iter {
println!("{}",item)
}
}
使用foreach配合閉包遍歷
fn main() {
let mut arr = Vec::new();
arr.push(1);
arr.push(2);
let item_iter = arr.iter();
item_iter.for_each(|x|println!("{}",x))
}
通過模擬hasNext進行遍歷
fn main() {
let mut arr = Vec::new();
arr.push(1);
arr.push(2);
let mut item_iter = arr.iter();
let mut i = item_iter.len();
while i != 0 {
println!("{}", item_iter.next().unwrap());
i = i - 1;
}
}
next方法
迭代器的next方法返回的是一個Option<T>
這樣一個對象
sum方法
這個方法一樣會消費迭代器,因為獲取迭代器的所有權(quán)并反復調(diào)用 next 來遍歷迭代器
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let total: i32 = v1_iter.sum();
迭代器適配器
Iterator trait 中定義了另一類方法,被稱為 迭代器適配器(iterator adaptors),他們允許我們將當前迭代器變?yōu)椴煌愋偷牡鳌?梢枣準秸{(diào)用多個迭代器適配器。不過因為所有的迭代器都是惰性的,必須調(diào)用一個消費適配器方法以便獲取迭代器適配器調(diào)用的結(jié)果。
fn main() {
let mut arr = Vec::new();
arr.push(1);
arr.push(2);
let new_arr:Vec<_> = arr.iter().map(|x| x + 4).collect();
println!("{:?}", new_arr);
}
這里我們使用map對迭代器中的每個元素進行操作,最后使用collect收集為新的集合類型文章來源:http://www.zghlxwxcb.cn/news/detail-421614.html
迭代器的性能
實際上迭代器更快,因為迭代器,作為一個高級的抽象,被編譯成了與手寫的底層代碼大體一致性能代碼。迭代器是 Rust 的 零成本抽象(zero-cost abstractions)之一,它意味著抽象并不會引入運行時開銷
詳細大家可以看這里:
https://kaisery.github.io/trpl-zh-cn/ch13-04-performance.html文章來源地址http://www.zghlxwxcb.cn/news/detail-421614.html
到了這里,關(guān)于研讀Rust圣經(jīng)解析——Rust learn-11(測試,迭代器,閉包)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!