精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Rust語言中閉包的應用場景

科技綠洲 ? 來源:TinyZ ? 作者:TinyZ ? 2023-09-20 11:25 ? 次閱讀

Rust語言的閉包是一種可以捕獲外部變量并在需要時執行的匿名函數。閉包在Rust中是一等公民,它們可以像其他變量一樣傳遞、存儲和使用。閉包可以捕獲其定義范圍內的變量,并在必要時訪問它們。這使得閉包在許多場景下非常有用,例如迭代器、異步編程和并發編程。

閉包與函數的區別在于,閉包可以捕獲它所定義的環境中的變量。這意味著,當閉包中使用變量時,它可以訪問該變量的值。在Rust中,閉包被設計為可以自動推斷變量的類型,因此可以方便地使用。

Rust閉包概念和python中Lambda表達式,Java的Lambda表達式很類似,可以幫助理解和應用。

閉包的應用場景

閉包在Rust語言中被廣泛應于許多場景。例如,在多線程編程中,閉包可以用來定義線程任務。在Web開發中,閉包可以用來定義路由處理函數。在數據處理領域,閉包可以用來定義數據轉換和過濾函數等等。 下面,我們以Animal為例,演示如何使用閉包實現一些常見的數據處理和轉換操作。

use std::collections::HashMap;

#[derive(Debug)]
struct Animal {
    name: String,
    species: String,
    age: i32,
}


impl Animal {
    fn new(name: &str, species: &str, age: i32) - > Self {
        Animal {
            name: name.to_owned(),
            species: species.to_owned(),
            age,
        }
    }
}

impl Display for Animal {
    fn fmt(&self, f: &mut Formatter) - > Result {
        write!(f, "Animal info name {}, species:{}, age:{}", self.name, self.species, self.age)
    }
}

fn main() {
    let animals = vec![
        Animal::new("Tom", "Cat", 2),
        Animal::new("Jerry", "Mouse", 1),
        Animal::new("Spike", "Dog", 3),
    ];

    // 計算所有動物的平均年齡
    let total_age = animals.iter().map(|a| a.age).sum::< i32 >();
    let average_age = total_age as f32 / animals.len() as f32;
    println!("Average age: {:.2}", average_age);

    // 統計每個物種的數量
    let mut species_count = HashMap::new();
    for animal in &animals {
        let count = species_count.entry(animal.species.clone()).or_insert(0);
        *count += 1;
    }
    println!("Species count: {:?}", species_count);

    // 找出所有年齡大于2歲的動物
    let old_animals: Vec< _ > = animals.iter().filter(|a| a.age > 2).collect();
    println!("Old animals: {:?}", old_animals);

    // 將所有動物的名字轉換成大寫
    let upper_names: Vec< _ > = animals.iter().map(|a| a.name.to_uppercase()).collect(); 
    println!("Upper case names {:?}", upper_names);
}
//    輸出結果:
// Average age: 2.00
// Species count: {"Dog": 1, "Cat": 1, "Mouse": 1}
// Old animals: [Animal { name: "Spike", species: "Dog", age: 3 }]
// Upper case names ["TOM", "JERRY", "SPIKE"]

在上面的代碼中,我們定義了一個Animal結構體,其中包含了動物的名稱、物種和年齡信息。我們使用Vec類型來存儲所有動物的信息。接下來,我們使用包對這些動物進行了一些常見的數據處理和轉換操作。

首先,我們計算了所有動物的平均年齡。我們使用iter()方法對Vec進行迭代,并使用map()方法將每個動物的年齡提取出來。然后,我們使用sum()方法將所有的年齡相加,并將其轉換為i32類型。最后,我們將總年齡除以動物數量,得到平均年齡。

接下來,我們統計了每個物種的數量。我們使用HashMap類型來存儲物種和數量的映射關系。我們使用entry方法獲取每個物種的數量,如果該物種不存在,則插入一個新的映射關系,并將數量初始化為0。最后,我們使用filter()方法和閉包找出了所有年齡大于2歲的動物。我們使用map()方法和閉包將所有動物的名字轉換成大寫,然后使用collect()方法將它們收集到一個新的Vec中。最后,我們使用map()方法和閉包將所有動物的名字轉換成大寫。

在上面的示例中,我們可以看到閉包的強大之處。使用閉包,我們可以輕松地對數據進行轉換和處理,而不必定義大量的函數。此外,閉包還可以捕獲外部環境中的變量,使得代碼更加靈活和可讀。

閉包的語法

包的語法形式如下:

|arg1, arg2, ...| body

其中,arg1arg2...表示閉包參數body表示閉包函數體。閉包可以有多個參數,也可以沒有參數。如果閉包沒有參數,則可以省略||之間的內容。

無參數閉包示例:

fn main() {
    let greet = || println!("Hello, World!");
    greet();
}
//    輸出結果:
//    Hello, World!

閉包的函數體可以是任意有效的Rust代碼,包括表達式、語句和控制流結構等。在閉包中,我們可以使用外部作用域中的變量。這些變量被稱為閉包的自由變量,因為它們不是閉包參數,但是在閉包中被引用了。

閉包的自由變量示例如下:

fn main() {
    let x = 3;
    let y = 5;
    //  在這里y,就是閉包的自由變量  
    let add = |a, b| a + b + y;
    
    println!("add_once_fn: {}", add(x,y));
}
//    輸出結果:
//    13

在上面的示例中,我們定義了一個閉包add,沒用指定參數的具體類型,這里是使用到了Rust語言的閉包類型推導特性,編譯器會在調用的地方進行類型推導。這里值得注意的幾點小技巧定義的閉包必須要有使用,否則編譯器缺少類型推導的上下文。當編譯器推導出一種類型后,它就會一直使用該類型,和泛型有本質的區別。

//    1. 將上面例子的pringln!注釋掉, 相當于add閉包沒用任何引用,編譯報錯
error[E0282]: type annotations needed
  -- > src/main.rs:13:16
   |
13 |     let add = |a, b| a + b + y;
   |                ^
   |
help: consider giving this closure parameter an explicit type
   |
13 |     let add = |a: /* Type */, b| a + b + y;
   |                 ++++++++++++
//    2. 新增打印 println!("add_once_fn: {}", add(0.5,0.6));

error[E0308]: arguments to this function are incorrect
  -- > src/main.rs:16:33
   |
16 |     println!("add_once_fn: {}", add(0.5,0.6));
   |                                 ^^^ --- --- expected integer, found floating-point number
   |                                     |
   |                                     expected integer, found floating-point number
   |
note: closure defined here
  -- > src/main.rs:13:15
   |
13 |     let add = |a, b| a + b + y;
   |               ^^^^^^

閉包可以使用三種方式之一來捕獲自由變量:

  • ? move關鍵字:將自由變量移動到閉包內部,使得閉包擁有自由變量的所有權。這意味著,一旦自由變量被移動,部作用域將無法再次使用它。
  • ? &引用:使用引用來訪問自由變量。這意味著,外部作用域仍然擁有自由變量的所有權,并且可以在閉包之后繼續使用它。
  • ? &mut可變引用:使用可變引用來訪問自由變量。這意味著,外部作用域仍然擁有自由變量的所有權,并且可以在閉包之后繼續使用它。但是,只有一個可變引用可以存在于任意給定的時間。如果閉包中有多個可變引用,編譯器將無法通過。

下面是具有不同捕獲方式的閉包示例:

fn main() {
    let x = 10;
    let y = 20;
    
    // 使用move關鍵字捕獲自由變量
    let add = move |a:i32, b:i32| a + b + x;
    
    // 使用引用捕獲自由變量
    let sub = |a:i32, b:i32| a - b - y;
    
    // 使用可變引用捕獲自由變量
    let mut z = 30;
    let mut mul = |a:i32, b:i32| {
        z += 1;
        a * b * z
    };
    println!("add {}", add(x, y))
    println!("sub {}", sub(x, y))
    println!("mul {}", mul(x, y))
}
//    輸出結果:
// add 40
// sub -30
// mul 6200

在上面的示例中,我們定義了三個閉包:addsubmul

  • ? add使用move關鍵字捕獲了自由變量x,因此它擁有x的所有權。
  • ? sub使用引用捕獲了自由變量y,因此它只能訪問y的值,而不能修改它。
  • ? mul使用可變引用捕獲了自由變量z,因此它可以修改z的值。在這種情況下,我們需要使用mut關鍵字來聲明可變引用。

閉包的類型

在Rust語言中,閉包是一種特殊的類型,被稱為FnFnMutFnOnce。這些類型用于區分閉包的捕獲方式和參數類型。

  • ? Fn:表示閉包只是借用了自由變量,不會修改它們的值。這意味著,閉包可以在不擁有自由變量所有權的情況下訪問它們。
  • ? FnMut:表示閉包擁有自由變量的可變引用,并且可能會修改它們的值。這意味著,閉包必須擁有自由變量的所有權,并且只能存在一個可變引用。
  • ? FnOnce:表示閉包擁有自由變量的所有權,并且只能被調用一次。這意味著,閉包必須擁有自由變量的所有權,并且只能在調用之后使用它們。

在閉包類型之間進行轉換是非常簡單的。只需要在閉包的參數列表中添加相應的trait限定,即可將閉包轉換為特定的類型。例如,如果我們有一個Fn類型的閉包,但是需要將它轉換為FnMut類型,只需要在參數列表中添加mut關鍵字,如下所示:

fn main() {
    let x = 3;
    let y = 5;
    let add = |a:i32, b:i32| a + b;
    let mut add_mut = |a:i32, b:i32| {
        let result = a + b;
        println!("Result: {}", result);
        result
    };
    
    let add_fn: fn(i32, i32) - > i32 = add;
    let add_mut_fn: fn(i32, i32) - > i32 = add_mut;
    let add_once_fn: fn(i32, i32) - > i32 = |a:i32, b:i32| a + b + 10;
    println!("add_fn: {}", add_fn(x,y));
    println!("add_mut_fn: {}", add_mut_fn(x,y));
    println!("add_once_fn: {}", add_once_fn(x,y));
}
//    輸出結果:
// add_fn: 8
// Result: 8
// add_mut_fn: 8
// add_once_fn: 18

在上面的示例中,我們定義了三個閉包:addadd_mutadd_onceaddadd_mut都是Fn類型的閉包,但是add_mut使用了可變引用,因此它也是FnMut類型閉包。我們使用fn關鍵字將閉包轉換為函數類型,并指定參數和返回值的類型。在這種情況下,我們使用i32作為參數和返回值的類型。

閉包的應用與實踐

閉包在Rust語言中廣泛應用于函數式編程、迭代器和多線程等領域。在函數式編程中,閉包常常用于實現高階函數,如map()filter()reduce()等。這些函數可以接受一個閉包作為參數,然后對集合中的每個元素進行轉換、過濾和歸約等操作。

以下是一個使用閉包實現map()filter()函數的示例:

fn map< T, F >(source: Vec< T >, mut f: F) - > Vec >
where
    F:Mut(T) - > T,
{
    let mut result = Vec::new();
    for item in source {
        result.push(f(item));
    }
    result
}

fn filter< T, F >(source: Vec< T >, mut f: F) - > Vec< T >
where
    F: FnMut(&T) - > bool,
{
    let mut result = Vec::new();
    for item in source {
        if f(&item) {
            result.push(item);
        }
    }
    result
}

在上面的示例中,我們定義了map()filter()函數,它們接受一個閉包作為參數,并對集合中的每個元素進行轉換和過濾操作。map()函數將集合中的每個元素傳遞給閉包進行轉換,并將轉換后的結果收集到一個新的Vec中。filter()函數將集合中的每個元素傳遞給閉包進行過濾,并將通過過濾的元素收集到一個新的Vec中。

以下是一個使用閉包實現多線程的示例:

use std::thread;

fn main() {
    let mut handles = Vec::new();
    for i in 0..10 {
        let handle = thread::spawn(move || {
            println!("Thread {}: Hello, world!", i);
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
}
//    輸出結果:
// Thread 1: Hello, world!
// Thread 7: Hello, world!
// Thread 8: Hello, world!
// Thread 9: Hello, world!
// Thread 6: Hello, world!
// Thread 5: Hello, world!
// Thread 4: Hello, world!
// Thread 3: Hello, world!
// Thread 2: Hello, world!
// Thread 0: Hello, world!

在上面的示例中,我們使用thread::spawn()函數創建了10個新線程,并使用閉包將每個線程的編號傳遞給它們。在閉包中,我們使用move關鍵字將i移動到閉包內部,以便在創建線程之后,i的所有權被轉移 給了閉包。然后,我們將每個線程的句柄存儲在一個Vec中,并使用join()函數等待每個線程完成。

總結

Rust語言中的閉包是一種非常強大的特性,可以用于實現高階函數、函數式編程、迭代器和多線程等領域。閉包具有捕獲自由變量的能力,并且可以在閉包后繼續使用它們。在Rust語言中,閉包是一種特殊的類型,被稱為FnFnMutOnce,用于區閉包的捕獲方式和參數類型。閉包可以通過實現這些trait來進行類型轉換。

盡管閉包在Rust語言中非常強大和靈活,但是使用它們時需要謹慎。閉包的捕獲方式和參數類型可能會導致所有權和可變性的問題,尤其是在多線程環境中。因此,我們應該在使用閉包時仔細思考,并遵循Rust語言的所有權和可變性規則。

總之,閉包是一種非常有用的特性,可以幫助我們編寫更加靈活和高效的代碼。如果您還沒有使用過閉包,請嘗試在您的項目中使用它們,并體驗閉包帶來的便利和效率。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 存儲
    +關注

    關注

    13

    文章

    4266

    瀏覽量

    85686
  • 編程
    +關注

    關注

    88

    文章

    3596

    瀏覽量

    93610
  • 數據處理
    +關注

    關注

    0

    文章

    583

    瀏覽量

    28531
  • rust語言
    +關注

    關注

    0

    文章

    57

    瀏覽量

    3006
  • 閉包
    +關注

    關注

    0

    文章

    4

    瀏覽量

    2048
收藏 人收藏

    評論

    相關推薦

    聊聊Rust與C語言交互的具體步驟

    rust FFI 是rust與其他語言互調的橋梁,通過FFI rust 可以有效繼承 C 語言的歷史資產。本期通過幾個例子來聊聊
    發表于 07-06 11:15 ?1673次閱讀

    C語言中預定義宏的用法和使用場景

    在C語言中,預定義宏是由編譯器提供的一組特殊標識符,可以在程序中直接使用,無需進行額外的定義。
    發表于 08-16 16:12 ?450次閱讀

    如何在Rust中高效地操作文件

    Rust語言是一種系統級、高性能的編程語言,其設計目標是確保安全和并發性。 Rust語言以C和C++為基礎,但是對于安全性和并發性做出了很大
    的頭像 發表于 09-19 11:51 ?2349次閱讀

    SQLx在Rust語言中的基礎用法和進階用法

    SQLx是一個Rust語言的異步SQL執行庫,它支持多種數據庫,包括MySQL、PostgreSQL、SQLite等。本教程將以MySQL數據庫為例,介紹SQLx在Rust語言中的基礎
    的頭像 發表于 09-19 14:32 ?5112次閱讀

    Rust語言中錯誤處理的機制

    Rust語言中,錯誤處理是一項非常重要的任務。由于Rust語言采用靜態類型檢查,在編譯時就能發現很多潛在的錯誤,這使得程序員能夠更加自信和高效地開發程序。然而,即使我們在編譯時盡可能
    的頭像 發表于 09-19 14:54 ?1367次閱讀

    基于Rust語言Hash特征的基礎用法和進階用法

    Rust語言是一種系統級編程語言,具有高性能、安全、并發等特點,是近年來備受關注的新興編程語言。在Rust
    的頭像 發表于 09-19 16:02 ?1386次閱讀

    Rust語言中的反射機制

    Rust語言的反射機制指的是在程序運行時獲取類型信息、變量信息等的能力。Rust語言中的反射機制主要通過 Any 實現。 std::any::Any trait Any trait是所
    的頭像 發表于 09-19 16:11 ?2288次閱讀

    Rust語言如何與 InfluxDB 集成

    Rust 是一種系統級編程語言,具有高性能和內存安全性。InfluxDB 是一個開源的時間序列數據庫,用于存儲、查詢和可視化大規模數據集。Rust 語言可以與 InfluxDB 集成,
    的頭像 發表于 09-30 16:45 ?1111次閱讀

    基于Rust語言中的生命周期

    Rust是一門系統級編程語言具備高效、安和并發等特,而生命周期是這門語言中比較重要的概念之一。在這篇教程中,我們會了解什么是命周期、為什么需要生命周期、如何使用生命周期,同時我們依然會使用老朋友
    的頭像 發表于 09-19 17:03 ?875次閱讀

    Rust 語言中的 RwLock內部實現原理

    Rust是一種系統級編程語言,它帶有嚴格的內存管理、并發和安全性規則,因此很受廣大程序員的青睞。RwLock(讀寫鎖)是 Rust 中常用的線程同步機制之一,本文將詳細介紹 Rust
    的頭像 發表于 09-20 11:23 ?833次閱讀

    用最簡單的語言解釋Python的是什么?

    很藍瘦,你應該盡量理解一下它。
    的頭像 發表于 03-21 16:33 ?2094次閱讀

    詳細介紹go語言中的實現

    什么是? 什么場景下會用 ? 本文對 go 語言中
    的頭像 發表于 10-20 16:18 ?1843次閱讀

    帶你了解go語言中

    ? 【 導讀】什么是? 什么場景下會用 ? 本文對 go 語言中
    的頭像 發表于 11-02 15:27 ?2414次閱讀

    谷歌開源內部Rust Crate審計結果

    Rust 可以輕松地將代碼封裝和共享到 crate 中,crate 是可重用的軟件組件,就像其他語言中一樣。我們擁抱廣泛的開源 Rust crate 生態系統,既利用了谷歌以外編
    的頭像 發表于 05-29 11:10 ?779次閱讀

    tokio模塊channel中的使用場景和優缺點

    以讓不同的線程之間通過發送和接收消息來傳遞數據,從而實現線程之間的協作和同步。 在 Rust 語言中,tokio 模塊的 channel 組件提供了
    的頭像 發表于 09-19 15:54 ?750次閱讀