Rust 迭代器的 10 個示例

Rust 迭代器功能強大且靈活。一旦掌握了它們,你就可以寫出簡潔靈活的代碼。下面是展示 Rust 迭代器功能的 10 個示例。

1,讓我們從一個簡單的示例開始,把從 1 到 10 的數的平方和相加。

範圍 (1..=10) 本身被用作這裏的初始迭代器,產生數字 1 到 10。然後我們使用 map 方法和閉包將參數與自身相乘,生成參數的平方。Map 返回一個包含平方和列表的新迭代器,我們用求和法把所有的平方和加起來,Sum 返回一個值。

fn main() {
    let sum_of_squares: i32 = (1..=10).map(|x| x * x).sum();
    println!("Sum of squares: {}", sum_of_squares);
}

2,使用 filter 方法在特定範圍內過濾出偶數

Filter 是一個方法,它接受一個條件閉包,並且只返回閉包返回 true 的元素。filter 返回另一個迭代器,這就是爲什麼我們在最後調用 collect 來將所有元素收集到 Vec 中。

fn main() {
    let even_numbers: Vec<_> = (1..=10).filter(|x| x % 2 == 0).collect();
    println!("Even numbers: {:?}", even_numbers);
}

3,在這個例子中,我們使用 std::iter 模塊中的輔助函數 successors 來計算著名的斐波那契數列

successors 創建了一個帶有兩個參數的迭代器,第一個參數是開始值,另一個參數是每次從迭代器中獲取另一個元素時調用的閉包。閉包將前一個元素作爲唯一參數,該值被包裝在一個 Option 中,因此當迭代器中沒有後繼對象時,它可以發出信號。閉包使用元組 (a,b) 來跟蹤前一個值以計算下一個值。這就是 map 添加到迭代器鏈的原因,Map 接受元組,並且只返回每個元組的第一個元素。我們使用 take 將迭代次數限制爲 10 次。

fn main() {
    let fib = std::iter::successors(Some((0, 1))|(a, b)| Some((*b, *a + *b)))
        .map(|(a, _)| a)
        .take(10);
    for num in fib {
        println!("{}", num);
    }
}

4,如何計算質數

這裏我們創建了一個 helper 函數來檢查它的參數是否爲質數,is_primeis 使用迭代器方法 all,它使用迭代器並接受一個閉包,該閉包檢查所有元素。顧名思義,只有閉包對所有元素都返回 true 時,all 方法才返回 true。這裏 all 用於檢查輸入數 n 是否不能被 2 到根號 (n) 之間的任何數整除,在這種情況下,這個數是素數。在 main 函數中,我們使用帶有 is_prime 函數作爲條件的 filter 來過濾素數。最後使用 collect 創建一個 Vec。

fn is_prime(n: usize) -> bool {
    (2..=(n as f64).sqrt() as usize).all(|i| n % i != 0)
}

fn main() {
    let primes: Vec<_> = (2..=30).filter(|x| is_prime(*x)).collect();
    println!("Primes: {:?}", primes);
}

5,扁平化一個嵌套向量

使用 into_iter 方法將包含 vector 的輸入向量本身轉換爲迭代器。然後使用 flatten 方法遍歷它,將它扁平化爲單個迭代器。最後用 collect 方法轉換成一個新的向量。

fn main() {
    let nested_vectors = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
    let flattened: Vec<_> = nested_vectors.into_iter().flatten().collect();
    println!("Flattened: {:?}", flattened);
}

6,枚舉一個字符串列表

這裏我們使用 enumerate 方法創建一個迭代器,該迭代器生成包含輸入參數的索引和索引值的元組。這裏使用 for_each 方法對迭代器的每個元素調用閉包。

fn main() {
    vec!["apple""banana""cherry""date""fig""grape"]
        .into_iter()
        .enumerate()
        .for_each(|(i,w)| {println!("{}.{}",i+1,w)});
}

7,兩個數學向量 a 和 b 的和

在這個例子中,我們使用 zip 方法將兩個迭代器相互交織,創建一個新的迭代器,使用 map 生成每個迭代器中元素的元組,這些元組元素被添加在一起。結果將被收集到一個包含向量 a+b 的新 Vec 中。

fn main() {
    let vec1 = vec![1, 2, 3];
    let vec2 = vec![4, 5, 6];
    let result: Vec<_> = vec1.into_iter()
      .zip(vec2.into_iter()).map(|(a, b)| a + b).collect();
    println!("Sum: {:?}", result);
}

8,將一個列表摺疊成一個值

使用 fold 方法可以遍歷迭代器中的所有元素,fold 有兩個參數,第一個是初始值,第二個是一個有兩個參數的閉包:初始值和當前值。每次迭代的初始值都是前一次調用的返回值。顧名思義,將列表最後摺疊成一個值。我們也可以使用 product 方法代替 fold 方法。

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let product: i32 = numbers.into_iter().fold(1, |acc, x| acc * x);
    // 可以使用product()代替
    // let product: i32 = numbers.into_iter().product();
    println!("Product: {}", product);
}

9,找出第一個大於 3 的數

find 方法接受一個閉包,並返回閉包結果爲 true 的第一個元素,閉包本身接受一個參數。一個類似的方法是 position,它返回第一個閉包結果爲 true 的位置,而不是閉包爲真的值。

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let found = numbers.iter().find(|&&x| x > 3);
    // 返回位置
    // let found = numbers.iter().position(|&x| x > 3);
    println!("First number greater than 3: {:?}", found);
}

10,創建一幅撲克牌

flat_map 方法用於迭代器,將映射操作與扁平化操作結合起來。在我們的例子中,我們使用它來爲一副標準的 52 張撲克牌創建所有可能的等級和花色組合。這個例子比其他例子稍微複雜一點,所以這裏有它的工作原理的詳細描述。正如你在這裏看到的,你也可以迭代普通數組。

fn main() {
    let suits = ["C""D""H""S"];
    let ranks = [
        "2""3""4""5""6""7""8""9""10""J""Q""K""A",
    ];

    let deck: Vec<String> = suits
        .iter()
        .flat_map(|suit| {
            ranks
                .iter()
                .map(move |rank| format!("{}{}", rank, suit))
        })
        .collect();

    println!("Deck of cards: {:?}", deck);
}

對於 suits 數組中的每一種花色,flat_map 接受一個閉包,該閉包接收花色作爲參數 (在本例中,它是 | suit|)。

在閉包內部,我們使用 ranks.iter() 創建一個新的迭代器。這個迭代器遍歷 rank 數組中的所有 rank。

然後在 ranks 迭代器上應用 map 方法。閉包'move |rank|format!("{}{}", rank, suit)'爲每個 rank 執行。move 關鍵字用於按值捕獲 suit 變量,允許它在閉包中使用。format! 宏用於通過連接 rank 和花色來爲每張牌創建字符串表示。

最後,flat_map 將所有這些單獨的 suit 迭代器組合成一個迭代器,有效地將結構變得平坦。結果迭代器現在產生所有 52 張撲克牌。

總結

Rust 迭代器是一個功能強大的構造,它允許開發人員以一種高度表達、高效和可組合的方式處理數據序列。

以下是 Rust 迭代器最重要的優點和特性:

1,可組合性:迭代器可以使用 map、filter、flat_map、chain、zip 等方法輕鬆組合。這使得開發人員可以用簡單易讀的代碼創建複雜的數據轉換。

2,惰性求值:迭代器在使用值時實時計算值,確保只處理所需的元素。這會帶來顯著的性能提升,特別是在處理大型或無限數據集時。

3,可讀性:通過使用迭代器方法,開發人員可以編寫與他們要解決的問題非常相似的代碼。這使得代碼更易於閱讀和理解,從而減少錯誤和提高代碼的可維護性。

4,靈活性:Rust 迭代器可用於廣泛的數據結構,如數組、向量、鏈表等。它們還支持自定義數據類型,允許開發人員爲特定的用例創建自己的迭代器實現。

5,抽象:迭代器抽象了數據遍歷的細節,使你能夠專注於對數據執行的操作,而不是遍歷本身的機制。這樣可以得到更清晰、更易維護的代碼。另一方面,循環通常需要手動索引或迭代,這可能會導致錯誤或其他問題。

6,統一接口:迭代器爲處理不同類型的數據結構提供了一致的接口。這使得編寫可以處理各種數據類型 (如數組、向量、字符串和鏈表) 的泛型代碼變得更容易。傳統的循環對於不同的數據結構通常需要不同的方法,這可能會使代碼更加複雜和難以維護。

7,減少錯誤:通過抽象出數據遍歷的細節,使用迭代器可以幫助減少常見錯誤的可能性,例如位置差一錯誤或索引越界問題。這使得開發人員可以專注於數據處理邏輯,而不是管理循環變量和索引。

8,性能:Rust 迭代器在設計時就考慮到了性能。Rust 編譯器內聯了許多迭代器方法,與傳統循環相比,這可以顯著提高性能。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Jp3AqGxIdELlhLNRkHvcag