首頁 > 軟體

Rust for迴圈語法糖背後的API場景分析

2022-11-07 14:00:16

Rust中for迴圈實質上是一個語法糖,in後面的物件要求是一個迭代器,for迴圈就是對這個迭代器迴圈呼叫next,而in前面的名稱就是每一次迭代後返回的結果,如果next返回Option::None則退出迴圈。瞭解這一點後我們可以自己編寫自己的迭代器型別,然後使用for迴圈進行迭代。

rust有三種for迴圈,分別用於不同的場景。

1.拿走所有權的for迴圈

形式如:for item in collection(集合或容器型別)會拿走collection的所有權(ownership)

fn main() {
    let collection: Vec<i32> = vec![1, 2, 4, 6, 9];

    // 注意這兒的item型別是i32
    for item in collection {
        println!("item:{}", item);
    }

    // for迴圈之後,不能再使用collection,因為collection的所有權已經被拿走,且在for迴圈後collection已經被drop掉了
    // println!("collection:{:?}", collection);
}

因為rust編譯器會將for item in collection替換成for item in IntoIterator::into_iter(collection)

fn main() {
    let collection: Vec<i32> = vec![1, 2, 4, 6, 9];

    // rust中的into_開頭的方法一般情況下都會拿走引數的所有權
    let iter = IntoIterator::into_iter(collection);
    // 從這兒開始,collection已經不能再被使用,因為collection的所有權被轉移到into_iter方法中,當方法執行完,collection就被drop掉了 
    // println!("collection:{:?}", collection); // 如果這兒使用collection就會編譯報錯
    for item in iter{
        println!("item:{}", item);
    }
}

正如Rust官網https://doc.rust-lang.org/std/iter/trait.IntoIterator.html上說的:One benefit of implementing IntoIterator is that your type will work with Rust’s for loop syntax.,即實現IntoIterator trait能夠讓你自定義型別在for迴圈中使用。

Vec正是實現了IntoIterator,所以才可以在for迴圈中使用的:

2.唯讀for迴圈

形式如:for item in &collection,不會拿走collection的所有權,只會獲取它的不可變參照:

fn main() {
    let collection: Vec<i32> = vec![1, 2, 4, 6, 9];

    // 注意這兒item的型別是&i32,即它是對collection中元素的不可變參照
    for item in &collection {
        println!("item:{}", item);
    }

    println!("collection after for loop:{:?}", collection);
}

因為rust會將for item in &collection替換成for item in collection.iter():

fn main() {
    let collection: Vec<i32> = vec![1, 2, 4, 6, 9];

    // 注意這兒item的型別是&i32,即它是對collection中元素的不可變參照
    for item in collection.iter() { // 等價於for item in (&collection).iter() {
        println!("item:{}", item);
    }

    println!("collection after for loop:{:?}", collection);
}

迭代完集合中的元素後,集合還可以繼續使用。

3.讀寫for迴圈

形式如:for item in &mut collection,不會拿走collection的所有權,只會獲取它的可變參照:

fn main() {
    // 注意,為了修改collection中的元素,collection本身必須宣告為mut
    let mut collection: Vec<i32> = vec![1, 2, 4, 6, 9];

    // 注意這兒item的型別是&mut i32,即它是對collection中元素的可變參照
    for item in &mut collection {
        // 通過*對可變參照進行解除參照,從而可以修改參照指向的值
        *item = *item +1;
        println!("item:{}", item);
    }

    println!("collection after for loop:{:?}", collection);
}

上面的程式執行輸出:

item:2
item:3
item:5
item:7
item:10
collection after for loop:[2, 3, 5, 7, 10]

實現了對集合元素的修改。

因為rust會將for item in &mut collection替換成for item in collection.iter_mut():

fn main() {
    // 注意,為了修改collection中的元素,collection本身必須宣告為mut
    let mut collection: Vec<i32> = vec![1, 2, 4, 6, 9];

    // 注意這兒item的型別是&mut i32,即它是對collection中元素的可變參照
    for item in collection.iter_mut() { // 等價於for item in (&mut collection).iter_mut() {
        // 通過*對可變參照進行解除參照,從而可以修改參照指向的值
        *item = *item +1;
        println!("item:{}", item);
    }

    println!("collection after for loop:{:?}", collection);
}

參考資料:
1.《Rust實戰》(Rust In Action)

到此這篇關於Rust for迴圈語法糖背後的API的文章就介紹到這了,更多相關Rust for迴圈內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com