Go 语言中的一等函数

一等函数

什么是一等函数?

支持一等函数的编程语言允许将函数赋值给变量、作为参数传递给其它函数及从其他函数返回。 Go 支持一等函数。

我们将讨论一等函数的语法和各种用例。

匿名函数

让我们从一个将函数分配给变量的简单示例开始。

package main

import (  
    "fmt"
)

func main() {  
    a := func() {
        fmt.Println("hello world first class function")
    }
    a()
    fmt.Printf("%T", a)
}

在上面的程序中,在第8行中为变量a赋值了一个函数。这是将函数赋值给变量的语法。如果仔细注意,被赋值给的函数没有名称。这些类型的函数称为匿名函数,因为它们没有名称

调用此函数的唯一方法是使用变量 a。已经在下一行完成了这项工作。a() 调用该函数,这将打印 hello world first class function。 在第12行 我们变量 a 的类型。 这将打印 func()

运行此程序将打印

hello world first class function  
func() 

也可以调用匿名函数而不将其赋值给变量。让我们在下面的示例中看看这是如何实现的。

package main

import (  
    "fmt"
)

func main() {  
    func() {
        fmt.Println("hello world first class function")
    }()
}

在上面的程序中,第8行定义了一个匿名函数,在函数定义之后,我们立即使用第10行中的()调用该函数。该程序将输出,

hello world first class function  

也可以像任何其它函数一样将参数传递给匿名函数。

package main

import (  
    "fmt"
)

func main() {  
    func(n string) {
        fmt.Println("Welcome", n)
    }("Gophers")
}

在上面的程序中,一个字符串参数被传递给第10行中的匿名函数。运行此程序将打印,

Welcome Gophers  

用户定义的函数类型

就像我们定义自己的结构体类型一样,也可以定义自己的函数类型。

type add func(a int, b int) int 

上面的代码片段创建了一个新的函数类型 add,它接受两个整数参数并返回一个整数。 现在我们可以定义 add 类型的变量。

让我们编写一个程序来定义一个 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
    }
    s := a(5, 6)
    fmt.Println("Sum", s)
}

在上面的程序中,在第10行定义了一个add类型的变量a,并为其赋值了一个签名与add类型匹配的函数。我们调用第13行中的函数,并将结果赋值给s。该程序将打印,

Sum 11 

高阶函数

wiki中高阶函数的定义是一个至少执行以下操作之一的函数

  • 接受一个或多个函数作为参数
  • 返回一个函数作为其结果

让我们看一下上述两种场景的一些简单示例。

将函数作为参数传递给其它函数
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)
}

在上面的示例中,在第7行中,我们定义了一个函数simple,它接受一个接受两个int参数并返回一个int作为参数的函数。在第12行的main函数中,我们创建了一个匿名函数f,其签名与simple函数的参数匹配。我们调用simple,并在下一行将f作为参数传递给它。该程序将打印,

67
从其他函数返回函数

现在重写上面的程序并从simple函数返回一个函数。

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(60, 7))
}

在上面的程序中,第7行中的simple函数返回一个接受两个int参数并返回一个int参数的函数。

从第15行调用simple函数。simple的返回值被赋值给s。现在s包含simple函数返回的函数。调用s并在第16行中传递两个int参数。该程序将打印,

67

闭包

闭包是匿名函数的特例。闭包是访问在函数体外部定义的变量的匿名函数。

举个例子会让事情更清楚。

package main

import (  
    "fmt"
)

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

在上面的程序中,匿名函数访问第10行中位于其函数体外部的变量a。因此,该匿名函数是一个闭包。

每个闭包都绑定到它自己的周围变量。 让我们通过一个简单的例子来理解这意味着什么。

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返回一个闭包。这个闭包绑定到变量t。让我们了解一下这意味着什么。

第17、18行中声明的变量ab是闭包,它们绑定到自己的t值。

首先用参数World调用a。现在,at版本的值变成了Hello World

在第20行中,我们使用参数Everyone调用b。由于b绑定到自己的变量t,因此b版本的t的初始值也是Hello。因此,在该函数调用之后,bt版本的值变成Hello Everyone。程序的其余部分不言而喻。

该程序将打印,

Hello World  
Hello Everyone  
Hello World Gopher  
Hello Everyone !  

一等函数的实际使用

到目前为止,我们已经定义了什么是一等函数,并且已经看到了一些人为的例子来了解它们是如何工作的。 现在让编写一个具体的程序来展示一等函数的实际使用。

将创建一个程序,根据某些标准过滤一部分学生。 让我们一步一步来。

首先让定义student类型。

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

下一步是编写filter函数。此函数将一部分学生和一个确定学生是否符合筛选条件的函数作为参数。一旦编写了该函数,我们就会更好地理解它。让我们继续做吧。

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
}

在上面的函数中,filter的第二个参数是一个函数,它将student作为参数并返回布尔值。此函数用于确定特定学生是否符合标准。第3行中迭代student切片,并将每个学生作为参数传递给函数f。如果返回true,则表示学生已通过筛选条件,并将其添加到切片r。可能对该函数的实际用途有点困惑,但一旦完成程序,就会清楚。已经添加了主功能,并在下面提供了完整的程序。

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)
}

在主函数中,我们首先创建两个学生s1s2,并将它们添加到切片s中。现在我们想找出所有成绩为B的学生。在上面的程序中通过传递一个函数来确定这一点,该函数检查学生是否成绩为B,如果成绩为B,则返回true,作为第38行中filter函数的参数。上述程序将打印,

[{Samuel Johnson B USA}]

假设想找到所有来自印度的学生。 这可以通过更改到filter函数的函数参数来轻松完成。

在下面提供了执行此操作的代码,

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

请将其添加到主函数并检查输出。

让我们通过再编写一个程序来结束本节。 该程序将对切片的每个元素执行相同的操作并返回结果。 例如,如果我们想将切片中的所有整数乘以 5 并返回输出,则可以使用一等函数轻松完成。 这些对集合的每个元素进行操作的函数称为map函数。 我提供了下面的程序。 这是不言自明的。

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)
}

上面的程序将打印

[25 30 35 40 45]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值