一类函数
什么是一类函数?
支持一类函数的语言允许将函数分配给变量,作为参数传递给其他函数并从其他函数返回。 Go支持一类函数。
在本教程中,我们将讨论第一类函数的语法和各种用例。
匿名函数
让我们从一个简单的例子开始,它将一个函数赋给变量。
package main
import (
"fmt"
)
func main() {
a := func() {
fmt.Println("hello world first class function")
}
a()
fmt.Printf("%T", a)
}
在上面的程序中,我们为变量a
分配了一个函数。这是将函数赋值给变量的语法。 如果您仔细注意,分配给a
的函数没有名称。 这些函数称为匿名函数,因为它们没有名称。
调用此函数的唯一方法是使用变量a
。 我们已经在下一行完成了这项工作。 a()
调用该函数,这将打印hello world first class function
。我们打印变量a
的类型。 这将打印func()
。
运行此程序将输出
hello world first class function
func()
也可以在不将其分配给变量的情况下调用匿名函数。 让我们看看如何在以下示例中完成此操作。
package main
import (
"fmt"
)
func main() {
func() {
fmt.Println("hello world first class function")
}()
}
在上面的程序中,匿名函数在第8行中定义。在函数定义之后,我们在第10行中调用函数using()
。该程序将输出,
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
类型匹配的函数。将结果分配给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作为参数。 在主函数里面创建一个匿名函数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
的返回值分配给s
。 现在s
包含简单函数返回的函数。 我们调用s
并在第16行中传递两个int参数。该程序输出67。
闭包
闭包是匿名函数的特例。 闭包是匿名函数,用于访问函数体外定义的变量。
一个例子可以使事情变得更加清晰。
package main
import (
"fmt"
)
func main() {
a := 5
func() {
fmt.Println("a =", a)
}()
}
在上面的程序中,匿名函数访问变量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
。让我们理解这意味着什么。
变量a
和b
在第17和18行中声明为闭包,它们受到自己t
值的约束。
我们首先使用参数World
调用a
。 现在,t
的值变成了Hello World
。
我们用参数Everyone
调用b
。 由于b
与其自己的变量t
绑定,因此b
的t
初始值为Hello
。 因此,在此函数调用之后,b
的t
值变为Hello Everyone
。
这个程序将打印,
Hello World
Hello Everyone
Hello World Gopher
Hello Everyone !
一类函数的使用
到目前为止,我们已经定义了一类函数,我们已经看到一些例子来了解它们的工作原理。 现在让我们编写一个具体的程序,它显示了第一类函数的实际用法。
我们将创建一个程序,根据某些标准过滤一部分学生。 让我们一步一步地解决这个问题。
首先让我们定义学生类型。
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
}
在上面的函数中,要过滤的第二个参数是一个以学生为参数并返回bool的函数。 此功能确定特定学生是否符合标准。 我们在第一行中迭代学生切片。 我们将每个学生作为参数传递给函数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)
}
在main
函数中,我们首先创建两个学生s1
和s2
并将它们添加到切片s
中。 现在让我们找到所有B级学生。我们在上面的程序中通过传递一个函数来确定学生是否有B级,如果是,那么返回true,作为参数过滤函数,上述程序将打印,
[{Samuel Johnson B USA}]
假设我们想要找到所有来自印度的学生。 通过将函数参数更改为过滤函数,可以轻松完成此操作。
我提供了以下代码,
c := filter(s, func(s student) bool {
if s.country == "India" {
return true
}
return false
})
fmt.Println(c)
请将其添加到主函数并检查输出。
让我们再写一个程序来结束本节。 该程序将对切片的每个元素执行相同的操作并返回结果。 例如,如果我们想要将切片中的所有整数乘以5并返回输出,则可以使用第一类函数轻松完成。 这些对集合的每个元素进行操作的函数称为映射函数。 我已经提供了以下程序。
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]