自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入理解 Go 語(yǔ)言的一等函數(shù)及其應(yīng)用

開發(fā) 前端
Go 語(yǔ)言沒(méi)有面向?qū)ο笳Z(yǔ)言的語(yǔ)法,比如類 、繼承、對(duì)象,但 Go 語(yǔ)言中最重要的部分就是支持一等函數(shù)。

?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è)變量。

package main

import(
"fmt"
)

func main() {
a := func() {
fmt.Println("Learning first class Function")
}
a()

fmt.Printf("%T", a)
}

在上面的程序中,我們利用 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é)果:

Learning first class Function
func()

也可以調(diào)用匿名函數(shù)而不把它賦值給一個(gè)變量,讓我們來(lái)看一下下面的例子是如何做到這一點(diǎn)的:

package main

import (
"fmt"
)

func main() {
func() {
fmt.Println("Learing first class Function")
}()
}

在上面的程序中,在第 8 行定義了一個(gè)匿名函數(shù)。緊接著我們?cè)诘?10 行用 () 調(diào)用該函數(shù)。這個(gè)程序?qū)⑤敵?

Learing first class Function

也可以像其他函數(shù)一樣,向匿名函數(shù)傳遞參數(shù):

package main

import (
"fmt"
)

func main() {
func(n string) {
fmt.Println("Welcome to", n)
}("Gophers's World!")
}

我們?cè)谏厦娴拇a中,向匿名函數(shù)中傳入一個(gè) n string? 字符串參數(shù),然后在調(diào)用時(shí)傳入一個(gè) "Gophers's World!" ,此時(shí),運(yùn)行程序?qū)⒌玫饺缦碌慕Y(jié)果:

Welcome to Gophers's World!

3.用戶自定義的函數(shù)類型

就像我們自定義結(jié)構(gòu)體類型一樣,在 Go 語(yǔ)言中也支持自定義函數(shù)類型:

type add func(a int, b int) int

上面的代碼片段創(chuàng)建了一個(gè)新的函數(shù)類型 add?,它接受兩個(gè)整數(shù)參數(shù)并返回一個(gè)整數(shù),現(xiàn)在我們可以定義 add 類型的變量,如下的代碼:

package main

import (
"fmt"
)

type add func(a int, b int) int

func main() {
var a add = func(a int, b int) int {
return a + b
}

sum := a(2022, 10)
fmt.Println("a + b = ", sum)
}

上面的程序中,我們定義了一個(gè) add? 類型的變量,并給它分配了一個(gè)簽名與 add? 類型相符的函數(shù),接著通過(guò) sum := a(2022,10)? 調(diào)用并將結(jié)果賦給 sum,運(yùn)行程序后得到如下的結(jié)果:

a + b =  2032

4.高階函數(shù)

對(duì)高階函數(shù)的定義是這個(gè)函數(shù)至少做到以下的某一項(xiàng)的功能:

  • 以一個(gè)或者多個(gè)函數(shù)作為參數(shù)
  • 返回一個(gè)函數(shù)作為其結(jié)果

將函數(shù)作為參數(shù)傳遞給其他函數(shù)

package main

import (
"fmt"
)

func simple(a func(a, b int) int) {

fmt.Println(a(60, 7))
}

func main() {

f := func(a, b int) int {
return a + b
}

simple(f)
}

我們定義一個(gè)函數(shù) simple? 函數(shù),它接收兩個(gè) int 參數(shù),并返回一個(gè) int 參數(shù),然后把匿名函數(shù)傳給變量 f?,然后把 f 作為參數(shù)傳遞給 simple? 函數(shù),最終這個(gè)程序?qū)⒋蛴?nbsp;67 輸出:

67

從其他函數(shù)中返回函數(shù)

現(xiàn)在讓我們重寫上面的程序,從 simple 函數(shù)中返回一個(gè)函數(shù):

package main

import (
"fmt"
)

func simple() func(a, b int) int {

f := func(a, b int) int {
return a + b
}

return f
}

func main() {
s := simple()
fmt.Println(s(2022, 60))
}

運(yùn)行該程序,得到結(jié)果;

2082

5.閉包

閉包是匿名函數(shù)的一種特殊情況。閉包是匿名函數(shù),它訪問(wèn)定義在函數(shù)主體之外的變量。

代碼如下:

package main

import (
"fmt"
)

func main() {

a := 2022

func() {
fmt.Println("a = ", a)
}()
}

每個(gè)閉包都與它自己周圍的變量綁定。讓我們通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)理解這意味著什么。

package main

import (
"fmt"
)

func appendStr() func(string) string {
t := "Hello"
c := func(b string) string {
t = t + " " + b
return t
}
return c
}

func main() {
a := appendStr()
b := appendStr()
fmt.Println(a("World"))
fmt.Println(b("Everyone"))

fmt.Println(a("Gopher"))
fmt.Println(b("!"))
}

在上面的程序中,appendStr? 函數(shù)返回一個(gè)閉包。這個(gè)閉包被綁定到變量 t? 上,變量 a? 和 b? 是閉包,被綁定到它們自己的值 t 上。

我們傳遞參數(shù) World? 給 a?,然后 a? 的值變成了 Hello World。

傳遞參數(shù) Everyone? 給 b,然后 b? 的值變成了 Hello Everyone 。

Hello World  
Hello Everyone
Hello World Gopher
Hello Everyone !

閉包通常也是支持嵌套和 defer 工作的方法。在下面的例子中,我們可以看到一個(gè)允許我們嵌套工作的函數(shù)閉包:

package main

import (
"fmt"
"sort"
)

func main() {
input := []string{"foo", "bar", "baz"}
var result []string
// closure callback
func() {
result = append(input, "abc")
result = append(result, "def")
sort.Sort(sort.StringSlice(result))
}()
fmt.Println(result)
}

運(yùn)行結(jié)果:

[abc bar baz def foo]

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é)生類型:

type student struct {  
firstName string
lastName string
grade string
country string
}

下一步是編寫 filter 函數(shù)。這個(gè)函數(shù)以一個(gè)學(xué)生切片和一個(gè)確定學(xué)生是否符合過(guò)濾標(biāo)準(zhǔn)的函數(shù)為參數(shù)。如下:

func filter(s []student, f func(student) bool) []student {  
var r []student
for _, v := range s {
if f(v) == true {
r = append(r, v)
}
}
return r
}

在上述函數(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è)完整的程序:

package main

import (
"fmt"
)

type student struct {
firstName string
lastName string
grade string
country string
}

func filter(s []student, f func(student) bool) []student {
var r []student
for _, v := range s {
if f(v) == true {
r = append(r, v)
}
}
return r
}

func main() {
s1 := student{
firstName: "Naveen",
lastName: "Ramanathan",
grade: "A",
country: "India",
}
s2 := student{
firstName: "Samuel",
lastName: "Johnson",
grade: "B",
country: "USA",
}
s := []student{s1, s2}
f := filter(s, func(s student) bool {
if s.grade == "B" {
return true
}
return false
})
fmt.Println(f)
}

在主函數(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>

[{Samuel Johnson B USA}]

比方說(shuō),我們想找到所有來(lái)自印度的學(xué)生。這可以通過(guò)改變過(guò)濾器函數(shù)的參數(shù)來(lái)輕松實(shí)現(xiàn)。如下:

c := filter(s, func(s student) bool {  
if s.country == "India" {
return true
}
return false
})
fmt.Println(c)

讓我們?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è)程序

package main

import (
"fmt"
)

func iMap(s []int, f func(int) int) []int {
var r []int
for _, v := range s {
r = append(r, f(v))
}
return r
}
func main() {
a := []int{5, 6, 7, 8, 9}
r := iMap(a, func(n int) int {
return n * 5
})
fmt.Println(r)
}

運(yùn)行結(jié)果:

[25 30 35 40 45]

7.總結(jié)

在本文中,介紹了什么是一等函數(shù)的概念和功能,匿名函數(shù)、用戶自定義函數(shù)類型、高階函數(shù)和閉包,最后給出了一等函數(shù)的實(shí)際應(yīng)用例子,希望這篇文章對(duì)你有所幫助!

責(zé)任編輯:武曉燕 來(lái)源: 宇宙之一粟
相關(guān)推薦

2021-10-16 17:53:35

Go函數(shù)編程

2022-03-27 23:11:39

Go語(yǔ)言函數(shù)

2010-07-26 11:27:58

Perl閉包

2023-03-02 08:26:36

RedisAVL紅黑樹

2021-03-18 08:54:55

Go 語(yǔ)言函數(shù)

2023-10-27 11:27:14

Go函數(shù)

2021-06-30 17:55:34

Redis應(yīng)用跳表

2023-03-28 07:26:37

2024-04-07 00:04:00

Go語(yǔ)言Map

2024-10-11 11:54:14

C#編寫異步

2024-04-24 08:32:55

.NET對(duì)象映射

2021-04-20 23:25:16

執(zhí)行函數(shù)變量

2020-12-16 09:47:01

JavaScript箭頭函數(shù)開發(fā)

2010-06-28 10:12:01

PHP匿名函數(shù)

2019-11-05 10:03:08

callback回調(diào)函數(shù)javascript

2024-01-01 16:01:22

Python函數(shù)

2025-01-13 13:00:00

Go網(wǎng)絡(luò)框架nbio

2019-08-19 12:50:00

Go垃圾回收前端

2022-02-14 07:47:26

overlayfsdockerrootfs

2009-11-18 12:38:04

PHP字符串函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)