深入理解 Go 語(yǔ)言的一等函數(shù)及其應(yīng)用
?1.什么是 Go 中的一等函數(shù)
任何一門編程語(yǔ)言都離不開函數(shù),無(wú)論是命令式語(yǔ)言 C、多范式編程語(yǔ)言 C++,還是面向?qū)ο缶幊陶Z(yǔ)言 Java、Ruby,動(dòng)態(tài)語(yǔ)言 Python、JavaScript,函數(shù)這一語(yǔ)法元素都是當(dāng)仁不讓的核心。
Go 語(yǔ)言沒(méi)有面向?qū)ο笳Z(yǔ)言的語(yǔ)法,比如類 、繼承、對(duì)象,但 Go 語(yǔ)言中最重要的部分就是支持一等函數(shù)。
在 Go 語(yǔ)言中,函數(shù)式唯一一種基于特定輸入、實(shí)現(xiàn)特定任務(wù)并可反饋任務(wù)執(zhí)行結(jié)果的代碼塊。本質(zhì)上 Go 程序就是一組函數(shù)的集合。
什么是一等函數(shù)
一等函數(shù)允許將函數(shù)分配給變量(將函數(shù)通過(guò)變量進(jìn)行傳遞),作為參數(shù)傳遞給其他函數(shù),并從其他函數(shù)返回。
2.匿名函數(shù)
讓我們從一個(gè)簡(jiǎn)單的例子開始,它將一個(gè)函數(shù)分配給一個(gè)變量。
在上面的程序中,我們利用 a := func()? 給變量 a 分配了一個(gè)函數(shù),這是將一個(gè)函數(shù)賦值給一個(gè)變量的語(yǔ)法。
然后我們分配給 a 的函數(shù)并沒(méi)有名字,這類函數(shù)就被稱為匿名函數(shù)。
調(diào)用這個(gè)函數(shù)的唯一方法就是使用變量 a?,所以在后面使用 a()? 來(lái)調(diào)用這個(gè)函數(shù),這就會(huì)打印出 Learning first class Function;
然后我們打印變量 a? 的類型,這將打印出 func()。
運(yùn)行結(jié)果:
也可以調(diào)用匿名函數(shù)而不把它賦值給一個(gè)變量,讓我們來(lái)看一下下面的例子是如何做到這一點(diǎn)的:
在上面的程序中,在第 8 行定義了一個(gè)匿名函數(shù)。緊接著我們?cè)诘?10 行用 () 調(diào)用該函數(shù)。這個(gè)程序?qū)⑤敵?
也可以像其他函數(shù)一樣,向匿名函數(shù)傳遞參數(shù):
我們?cè)谏厦娴拇a中,向匿名函數(shù)中傳入一個(gè) n string? 字符串參數(shù),然后在調(diào)用時(shí)傳入一個(gè) "Gophers's World!" ,此時(shí),運(yùn)行程序?qū)⒌玫饺缦碌慕Y(jié)果:
3.用戶自定義的函數(shù)類型
就像我們自定義結(jié)構(gòu)體類型一樣,在 Go 語(yǔ)言中也支持自定義函數(shù)類型:
上面的代碼片段創(chuàng)建了一個(gè)新的函數(shù)類型 add?,它接受兩個(gè)整數(shù)參數(shù)并返回一個(gè)整數(shù),現(xiàn)在我們可以定義 add 類型的變量,如下的代碼:
上面的程序中,我們定義了一個(gè) add? 類型的變量,并給它分配了一個(gè)簽名與 add? 類型相符的函數(shù),接著通過(guò) sum := a(2022,10)? 調(diào)用并將結(jié)果賦給 sum,運(yùn)行程序后得到如下的結(jié)果:
4.高階函數(shù)
對(duì)高階函數(shù)的定義是這個(gè)函數(shù)至少做到以下的某一項(xiàng)的功能:
- 以一個(gè)或者多個(gè)函數(shù)作為參數(shù)
- 返回一個(gè)函數(shù)作為其結(jié)果
將函數(shù)作為參數(shù)傳遞給其他函數(shù)
我們定義一個(gè)函數(shù) simple? 函數(shù),它接收兩個(gè) int 參數(shù),并返回一個(gè) int 參數(shù),然后把匿名函數(shù)傳給變量 f?,然后把 f 作為參數(shù)傳遞給 simple? 函數(shù),最終這個(gè)程序?qū)⒋蛴?nbsp;67 輸出:
從其他函數(shù)中返回函數(shù)
現(xiàn)在讓我們重寫上面的程序,從 simple 函數(shù)中返回一個(gè)函數(shù):
運(yùn)行該程序,得到結(jié)果;
5.閉包
閉包是匿名函數(shù)的一種特殊情況。閉包是匿名函數(shù),它訪問(wèn)定義在函數(shù)主體之外的變量。
代碼如下:
每個(gè)閉包都與它自己周圍的變量綁定。讓我們通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)理解這意味著什么。
在上面的程序中,appendStr? 函數(shù)返回一個(gè)閉包。這個(gè)閉包被綁定到變量 t? 上,變量 a? 和 b? 是閉包,被綁定到它們自己的值 t 上。
我們傳遞參數(shù) World? 給 a?,然后 a? 的值變成了 Hello World。
傳遞參數(shù) Everyone? 給 b,然后 b? 的值變成了 Hello Everyone 。
閉包通常也是支持嵌套和 defer 工作的方法。在下面的例子中,我們可以看到一個(gè)允許我們嵌套工作的函數(shù)閉包:
運(yùn)行結(jié)果:
6.一等函數(shù)的實(shí)際應(yīng)用
到目前為止,我們已經(jīng)定義了什么是第一類函數(shù),我們也看到了一些精心設(shè)計(jì)的例子來(lái)學(xué)習(xí)它們是如何工作的?,F(xiàn)在讓我們來(lái)寫一個(gè)具體的程序,展示第一類函數(shù)的實(shí)際用途。
我們將創(chuàng)建一個(gè)程序,根據(jù)一些標(biāo)準(zhǔn)來(lái)過(guò)濾一部分學(xué)生。讓我們一步一步地去做。
首先讓我們定義學(xué)生類型:
下一步是編寫 filter 函數(shù)。這個(gè)函數(shù)以一個(gè)學(xué)生切片和一個(gè)確定學(xué)生是否符合過(guò)濾標(biāo)準(zhǔn)的函數(shù)為參數(shù)。如下:
在上述函數(shù)中,filter? 的第二個(gè)參數(shù)是一個(gè)函數(shù),它以一個(gè) student 為參數(shù),返回一個(gè) bool 。這個(gè)函數(shù)確定一個(gè)特定的學(xué)生是否符合某個(gè)標(biāo)準(zhǔn)。我們?cè)诘?3 行遍歷學(xué)生切片。如果該函數(shù)返回真,則意味著該學(xué)生通過(guò)了過(guò)濾標(biāo)準(zhǔn),并被添加到切片 r 中。
現(xiàn)在來(lái)看一個(gè)完整的程序:
在主函數(shù)中,我們首先創(chuàng)建了兩個(gè)學(xué)生 s1 和 s2,并將他們添加到片斷 s 中?,F(xiàn)在我們假設(shè)要找出所有成績(jī)?yōu)?B 的學(xué)生,在上述程序中,我們通過(guò)傳遞一個(gè)檢查學(xué)生是否為 B 級(jí)的函數(shù),如果是,則返回 true。 上述程序?qū)⒋蛴。?/p>
比方說(shuō),我們想找到所有來(lái)自印度的學(xué)生。這可以通過(guò)改變過(guò)濾器函數(shù)的參數(shù)來(lái)輕松實(shí)現(xiàn)。如下:
讓我們?cè)賹懸粋€(gè)程序來(lái)結(jié)束本文。這個(gè)程序?qū)?duì)一個(gè)切片的每個(gè)元素進(jìn)行同樣的操作,并返回結(jié)果。
例如,如果我們想將一個(gè)切片中的所有整數(shù)乘以 5,并返回輸出結(jié)果,可以用第一類函數(shù)輕松完成。
這類對(duì)集合中每個(gè)元素進(jìn)行操作的函數(shù)被稱為 map 函數(shù)。如下這個(gè)程序
運(yùn)行結(jié)果:
7.總結(jié)
在本文中,介紹了什么是一等函數(shù)的概念和功能,匿名函數(shù)、用戶自定義函數(shù)類型、高階函數(shù)和閉包,最后給出了一等函數(shù)的實(shí)際應(yīng)用例子,希望這篇文章對(duì)你有所幫助!