最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入了解Rust中函數(shù)與閉包的使用

 更新時間:2022年11月07日 09:29:02   作者:古明地覺  
本文主要介紹一下Rust函數(shù)相關的內容,首先函數(shù)我們其實一直都在用,所以函數(shù)本身沒什么可說的,我們的重點是與函數(shù)相關的閉包、高階函數(shù)、發(fā)散函數(shù),感興趣的可以學習一下

閉包

Rust 的閉包由一個匿名函數(shù)加上外層的作用域組成,舉個例子:

fn?main()?{
????let?closure?=?|n:?u32|?->?u32?{
????????n?*?2
????};
????println!("n?*?2?=?{}",?closure(12));
????//?n?*?2?=?24
}

閉包可以被保存在一個變量中,然后我們注意一下它的語法,參數(shù)定義、返回值定義都和普通函數(shù)一樣,但閉包使用的是兩個豎線。我們對比一下兩者的區(qū)別:

//?普通函數(shù)定義
fn?func1(a:?u32,?b:?u32)?->?String?{
????//?函數(shù)體
}
/*?如果換成閉包的話,那么等價于
let?func1?=?|a:?u32,?b:?u32|?->?String?{
????//?函數(shù)體
}
*/

所以兩者在語法上沒有什么本質的區(qū)別,但這個時候可能有人好奇了,我們能不能把閉包中的匿名函數(shù)換成普通函數(shù)呢?來試一下。

fn?main()?{
????let?closure1?=?|n:?u32|?->?u32?{
????????n?*?2
????};

????fn?closure2(n:?u32)?->?u32?{
????????n?*?2
????}

????println!("n?*?2?=?{}",?closure1(12));
????println!("n?*?2?=?{}",?closure2(12));
????/*
????n?*?2?=?24
????n?*?2?=?24
????*/
}

從表面上來看是可以的,但其實還存在問題,因為 closure2 只是一個在函數(shù)里定義的函數(shù)而已。而閉包除了要包含函數(shù)之外,還要包含函數(shù)所在的外層作用域,什么意思呢?我們舉例說明:

你看到了什么?沒錯,在函數(shù) closure2 內部無法使用外層作用域中的變量 a,因此它只是定義在 main 函數(shù)里的函數(shù)而已,而不是閉包,因為它不包含外層函數(shù)(main)的作用域。

而 Rust 提示我們使用 || { ... },那么 closure1 顯然是閉包,因為它除了包含一個函數(shù)(匿名),還包含了外層作用域,我們將這個閉包賦值給了 closure1。

此外閉包還有一個重要的用途,就是在多線程編程時,可以將主線程的變量移動到子線程內部。

關于多線程后續(xù)會詳細說,這里只是舉個例子。

//?導入線程模塊
use?std::thread;

fn?main()?{
????let?s?=?String::from("hello?world");
????//?必須在?||?的前面加上?move
????//?它的含義就是將值從主線程移動到子線程
????let?closure1?=?move?||?{
????????println!("{}",?s);
????};
????//?開啟一個子線程
????thread::spawn(closure1).join();
????/*
????hello?world
????*/
}

打印是發(fā)生在主線程當中的,而不是子線程,以上就是閉包相關的內容。

高階函數(shù)

了解完閉包之后,再來看看高階函數(shù),在數(shù)學和計算機中,高階函數(shù)是至少滿足下列一個條件的函數(shù):

  • 接收一個或多個函數(shù)作為輸入;
  • 輸出一個函數(shù);

在數(shù)學中它們也叫算子或者泛函,高階函數(shù)是函數(shù)式編程中非常重要的一個概念。

先來看看如何定義一個接收函數(shù)作為參數(shù)的函數(shù):

//?calc?接收三個參數(shù),返回一個?i32
//?參數(shù)一:接收兩個 i32 返回一個 i32 的函數(shù)
//?參數(shù)二?和?參數(shù)三均是一個?i32
fn?calc(method:?fn(i32,?i32)?->?i32,
????????a:?i32,?b:?i32)?->?i32?{
????method(a,?b)
}

fn?add(a:?i32,?b:?i32)?->?i32?{
????a?+?b
}
fn?main()?{
????println!("a?+?b?=?{}",?calc(add,?12,?33));
????/*
????a?+?b?=?45
????*/

????//?也可以傳遞一個匿名函數(shù),但它不能引用外層作用域的變量
????//?因為?calc?第一個參數(shù)接收的是函數(shù),不是閉包
????let?sub?=?|a:?i32,?b:?i32|?->?i32?{
????????a?-?b
????};

????println!("a?-?b?=?{}",?calc(sub,?12,?33));
????/*
????a?-?b?=?-21
????*/
}

以函數(shù)作為參數(shù),在類型聲明中我們不需要寫函數(shù)名以及參數(shù)名,只需要指明參數(shù)類型、數(shù)量和返回值類型即可。

然后再觀察一下函數(shù) calc 的定義,由于第一個參數(shù) method 接收一個函數(shù),所以它的定義特別的長,我們能不能簡化一下呢?

//?相當于給類型起了一個別名
type?Method?=?fn(i32,?i32)?->?i32;

fn?calc(method:?Method,
????????a:?i32,?b:?i32)?->?i32?{
????method(a,?b)
}

這種做法也是可以的。

看完了接收函數(shù)作為參數(shù),再來看看如何將函數(shù)作為返回值。

type?Method?=?fn(i32,?i32)?->?i32;

//?想要接收字符串的話
//?應該使用引用?&String?或切片?&str
//?當然我們前面說過,更推薦切片
fn?calc(op:?&str)?->?Method?{
????fn?add(a:?i32,?b:?i32)?->?i32?{
????????a?+?b
????}
????
????let?sub?=?|a:?i32,?b:?i32|?->?i32?{?a?-?b?};

????//?使用?if?else?也是可以的
????match?op?{
????????"add"?=>?add,
????????"sub"?=>?sub,
????????//?內置的宏,會拋出一個錯誤,表示方法沒有實現(xiàn)
????????_?=>?unimplemented!(),
????}  // 注意:此處不可以加分號,因為要作為表達式返回
}

fn?main()?{
????let?(a,?b)?=?(11,?33);
????println!("a?+?b?=?{}",?calc("add")(a,?b));
????println!("a?-?b?=?{}",?calc("sub")(a,?b));
????/*
????a?+?b?=?44
????a?-?b?=?-22
????*/
}

以上就是高階函數(shù),還是很好理解的,和 Python 比較類似。你可以基于這個特性,實現(xiàn)一個裝飾器,只是 Rust 里面沒有 @ 這個語法糖罷了。這里我們簡單地實現(xiàn)一下吧,加深一遍印象。

enum?Result?{
????Text(String),
????Func(fn()?->?String),
}

fn?index()?->?String?{
????String::from("歡迎來到古明地覺的編程教室")
}

fn?login_required(username:?&str,?password:?&str)?->?Result?{
????if?!(username?==?"satori"?&&?password?==?"123")?{
????????return?Result::Text(String::from("請先登錄"));
????}?else?{
????????return?Result::Func(index);
????}
}

fn?main()?{
????let?res1?=?login_required("xxx",?"yyy");
????let?res2?=?login_required("satori",?"123");
????//?如果后續(xù)還要使用?res1?和?res2,那么就使用引用
????//?也就是?[&res1,?&res2]
????//?但這里我們不用了,所以是?[res1,?res2],此時會轉移所有權
????for?item?in?[res1,?res2]?{
????????match?item?{
????????????Result::Text(error)?=>?println!("{}",?error),
????????????Result::Func(index)?=>?println!("{}",?index()),
????????}
????}
????/*
????請先登錄
????歡迎來到古明地覺的編程教室
????*/
}

是不是很有趣呢?這里再次看到了枚舉類型的威力,我們有可能返回字符串,也有可能返回函數(shù),那么應該怎么辦呢?很簡單,將它們放到枚舉里面即可,這樣它們都是枚舉類型。至于到底是哪一個成員,再基于 match 分別處理即可。

還記得 match 嗎?match 可以有任意多個分支,每一個分支都應該返回相同的類型,并且只有一個分支會執(zhí)行成功,然后該分支的返回值會作為整個 match 表達式的返回值。

發(fā)散函數(shù)

最后再來看看發(fā)散函數(shù),這個概念在其它語言里面應該很少聽到。在 Rust 里面,發(fā)散函數(shù)永遠不會返回,它的返回值被標記為 !,表示這是一個空類型。

//?發(fā)散函數(shù)的返回值類型是一個感嘆號
//?它表示這個函數(shù)執(zhí)行時會報錯
fn?foo()?->?!?{
????panic!("這個函數(shù)執(zhí)行時會報錯")
}

fn?main()?{
????//?調用發(fā)散函數(shù)時,可以將其結果賦值給任意類型的變量
????let?res1:?u32?=?foo();
????let?res2:?f64?=?foo();
}

所以這個發(fā)散函數(shù)沒啥卵用,你在實際開發(fā)中估計一輩子也用不上,因為它在執(zhí)行的時候會 panic 掉。所以這段代碼編譯的時候是沒有問題的,但執(zhí)行時會觸發(fā) panic。既然執(zhí)行時會報錯,那么當然可以賦值給任意類型的變量。

因此當返回值類型為 ! 時,我們需要通過 panic 宏讓函數(shù)在執(zhí)行的過程中報錯。但要注意的是,發(fā)散函數(shù)和不指定返回值的函數(shù)是不一樣的,舉個例子:

//?發(fā)散函數(shù)的返回值類型是一個感嘆號
//?它表示這個函數(shù)執(zhí)行時會報錯
fn?foo()?->?!?{
????panic!("這個函數(shù)執(zhí)行時會報錯");
}

//?不指定返回值,默認返回?()
//?所以以下等價于?fn?bar()?->?()?{}
//?但很明顯?bar?函數(shù)是有返回值的,會返回空元組
fn?bar()?{

}

總的來說發(fā)散函數(shù)沒啥卵用,在工作中也不建議使用,只要知道有這么個東西就行。

到此這篇關于深入了解Rust中函數(shù)與閉包的使用的文章就介紹到這了,更多相關Rust函數(shù) 閉包內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Rust的slab庫使用場景分析

    Rust的slab庫使用場景分析

    slab 是一個輕量級、高性能的工具,非常適合管理固定大小的資源集合,尤其是在網(wǎng)絡編程和事件驅動架構中,這篇文章主要介紹了Rust的slab庫使用教程,需要的朋友可以參考下
    2024-12-12
  • Rust中的引用與借用舉例詳解

    Rust中的引用與借用舉例詳解

    這篇文章主要給大家介紹了關于Rust中引用與借用的相關資料,rust中借用和引用的附帶功效都一樣,就是都有生命周期,文中通過代碼介紹的非常詳細,對大家學習或者使用Rust具有一定的參考價值,需要的朋友可以參考下
    2023-11-11
  • libbpf和Rust開發(fā)ebpf程序實戰(zhàn)示例

    libbpf和Rust開發(fā)ebpf程序實戰(zhàn)示例

    這篇文章主要為大家介紹了libbpf和Rust開發(fā)ebpf程序實戰(zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 詳解Rust中的所有權機制

    詳解Rust中的所有權機制

    Rust?語言提供了跟其他系統(tǒng)編程語言相同的方式來控制你使用的內存,但擁有數(shù)據(jù)所有者在離開作用域后自動清除其數(shù)據(jù)的功能意味著你無須額外編寫和調試相關的控制代碼,這篇文章主要介紹了Rust中的所有權機制,需要的朋友可以參考下
    2022-10-10
  • 使用systemd部署r-nacos的操作方法

    使用systemd部署r-nacos的操作方法

    r-nacos是一個用rust實現(xiàn)的nacos服務,我們用它平替java?nacos以降低服務占用內存,提升服務的穩(wěn)定性,這篇文章主要介紹了使用systemd部署r-nacos,需要的朋友可以參考下
    2024-03-03
  • Rust Atomics and Locks并發(fā)基礎理解

    Rust Atomics and Locks并發(fā)基礎理解

    這篇文章主要為大家介紹了Rust Atomics and Locks并發(fā)基礎理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Rust中的Drop特性之解讀自動化資源清理的魔法

    Rust中的Drop特性之解讀自動化資源清理的魔法

    Rust通過Drop特性實現(xiàn)了自動清理機制,確保資源在對象超出作用域時自動釋放,避免了手動管理資源時可能出現(xiàn)的內存泄漏或雙重釋放問題,智能指針如Box、Rc和RefCell都依賴于Drop來管理資源,提供了靈活且安全的資源管理方案
    2025-02-02
  • 利用Rust編寫一個簡單的字符串時鐘

    利用Rust編寫一個簡單的字符串時鐘

    這篇文章主要為大家詳細介紹了一個用rust寫的一個簡單的練手的demo,一個字符串時鐘,在終端用字符串方式顯示當前時間,感興趣的小伙伴可以了解一下
    2022-12-12
  • R語言ggplot2繪圖安裝與調試

    R語言ggplot2繪圖安裝與調試

    ggplot2是R語言中最常用的繪圖包之一,它提供了一種基于圖層的繪圖語法,使得用戶可以輕松地創(chuàng)建高質量的數(shù)據(jù)可視化圖表。在使用ggplot2之前,需要先安裝該包并進行調試。安裝ggplot2可以通過CRAN或GitHub進行,調試則需要注意數(shù)據(jù)格式、語法錯誤等問題。
    2023-06-06
  • Rust個人學習小結之Rust的循環(huán)

    Rust個人學習小結之Rust的循環(huán)

    這篇文章主要介紹了Rust個人學習小結之Rust的循環(huán),今天主要了解了Rust語言的3種循環(huán)方法:?loop、while、for,本文結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-01-01

最新評論

阿克| 北川| 务川| 娄底市| 建平县| 武陟县| 永胜县| 循化| 旺苍县| 蒙阴县| 灌阳县| 阿克陶县| 洞口县| 临沂市| 赤壁市| 云阳县| 会理县| 思南县| 措美县| 黄龙县| 虎林市| 汉沽区| 两当县| 库尔勒市| 临沧市| 永顺县| 舟山市| 科技| 榆中县| 平舆县| 西乌珠穆沁旗| 天长市| 英超| 犍为县| 永济市| 什邡市| 阿城市| 库尔勒市| 通城县| 丰原市| 卢氏县|