GO学习笔记——函数式编程(20)

编程入门 行业动态 更新时间:2024-10-11 07:33:14

GO学习笔记——<a href=https://www.elefans.com/category/jswz/34/1771370.html style=函数式编程(20)"/>

GO学习笔记——函数式编程(20)

在C中,我们有函数指针,函数指针可以作为参数传递给一个函数。

但是,在GO中,支持函数式编程,也就是说,它支持下面这个概念

头等函数:可以把函数赋值给变量,也可以把函数作为其他函数的返回值或者参数

所谓的函数是一等公民,也就是这么个意思。


匿名函数 

所谓的匿名函数,就是没有名字的函数。这和我们平时所了解的可能不一样,为什么一个函数可以没有名字?但这在函数式编程中,确实是可行的,因为我们可以将一个没有名字的函数赋值给一个变量使用。

func main() {a := func(){fmt.Println("Hello World!")}a()fmt.Printf("%T\n",a)
}

我们将一个匿名函数赋值给变量a,调用该函数的唯一方法就是变量a,a()调用了该函数,另外我们还打印了变量a的类型。

执行结果

Hello World!
func()

a的类型是一个func(),也就是说,变量a是一个函数。

使用匿名函数也可以不用一个变量来接收。

func main() {func(str string){fmt.Println(str)}("Hello World!")
}

可以在函数后面直接跟一个()来调用,并且和普通函数一样,在()内可以给这个匿名函数传参数

执行结果

Hello World!

 

高阶函数

  • 返回值是一个函数
  • 有一个或多个参数是函数

满足上面任意一个条件的函数就是高阶函数。

//定义一个sum函数,它的参数是一个func,返回值也是一个func
func sum(a func(a,b int) int) func(){result := a(1,2)return func() {fmt.Println(result)}
}func main() {a := func(a,b int) int {return a + b}sum(a)()	//sum(a)的返回值是一个函数,需要再用一个()来调用它
}

上面的sum函数,它的返回值是一个函数,它的参数也是一个函数,所以它是一个高阶函数。

注意,因为sum(a)调用完以后,得到的返回值也是一个函数,所以还需要再用一个()才可以得到我们想要的输出结果

执行结果

3

闭包

当一个匿名函数所访问的变量是定义在函数体的外部时,这样的匿名函数就是一个闭包

其实上面那个例子的函数就是一个闭包,因为在匿名函数中访问了result变量,而result是定义在匿名函数体外部的变量。

上面那个例子不能很好地突出闭包的概念,这里再来举一个例子。

//定义一个appendStr函数,可以追加字符串
func appendStr() func(string) string {v := "Hello"f := func (b string) string {v = v + " " + breturn v}return f
}func main() {a,b := appendStr(),appendStr()fmt.Println(a("LeBron"))fmt.Println(b("Kobe"))fmt.Println(a("James"))fmt.Println(b("Bryant"))
}

先看下执行结果

Hello LeBron
Hello Kobe
Hello LeBron James
Hello Kobe Bryant

函数appendStr返回了一个闭包,因为返回的匿名函数中调用了函数体外的变量v,因此该匿名函数就是一个闭包。

每一个闭包都绑定了一个外围变量,在这里v就是外围变量,因此,a和b闭包分别绑定了一个外围变量“Hello”。

首先用LeBron调用了闭包a,这个时候a中的外围变量就变成了“Hello LeBron”,闭包b也是同样的道理。

接着再用James调用了闭包a,这个时候a中的外围变量已经是更新过了的“Hello LeBron”,所以输出的“Hello LeBron James”,闭包b同理

 

用一张图来看看

所以在函数返回值是一个闭包的时候,它返回的不仅仅是一个匿名函数,而是一个闭包,闭包包括了这个匿名函数,同时闭包还保存了属于这个闭包的外围变量,对这个外围变量的引用会一直流传下去到后面的每一次调用。

是不是感觉,返回闭包,保存外围变量的这种功能,对于求斐波那契数列很有用?我试着实现了一下。

func fibonacci() func(index int) int {arr := []int{1,1}f := func (index int) int {if index < 2 {return arr[index]}else{arr = append(arr, arr[index - 1] + arr[index - 2])return arr[index]}}return f
}func main() {a := fibonacci()fmt.Println(a(0))fmt.Println(a(1))fmt.Println(a(2))fmt.Println(a(3))fmt.Println(a(4))
}

执行结果

1
1
2
3
5

在每次调用过程中,如果需要更新闭包的外围切片变量arr,那么每次更新的结果就都会被保存起来,所以就得到了如上的预期结果。


函数式编程实例

首先我们定义两个结构体

type student struct {name stringclass int
}type studentgrade struct {studentMath intEnglish intChinese intHistory int
}

一个是student结构体,包括name和class,另一个是studentgrede结构体,组合了student结构体,以及另外学生的四门成绩。

接下来我们定义一个filter函数,该函数用来过滤掉不满足条件的学生

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

filter函数的第一个参数是一个studentgrade切片,第二个参数是一个函数,这个函数其实就是一个过滤条件,filter函数的返回值是满足条件的学生的切片。

 

在main函数中,我们只需要设定好过滤条件就可以根据不同的过滤条件,用一个filter函数来过滤。

func main() {s1 := student{"pigff",1}s2 := student{"Kobe",2}s3 := student{"James",3}sg1 := studentgrade{s1,98,85,79,90}sg2 := studentgrade{s2,80,65,82,89}sg3 := studentgrade{s3,60,91,85,88}sg := []studentgrade{sg1,sg2,sg3}//找出数学成绩大于80的学生f := filter(sg,func(s studentgrade) bool{if s.Math > 80 {return true}return false})fmt.Println(f)
}

如上main函数的过滤条件就是找出数学成绩大于80的学生

执行结果

[{pigff 1}]

或者说,我们换一个过滤条件,找出英语和历史成绩都大于80分的同学,这个时候我们只要改变过滤条件函数就可以了。

func main() {s1 := student{"pigff",1}s2 := student{"Kobe",2}s3 := student{"James",3}sg1 := studentgrade{s1,98,85,79,90}sg2 := studentgrade{s2,80,65,82,89}sg3 := studentgrade{s3,60,91,85,88}sg := []studentgrade{sg1,sg2,sg3}//找出英语和历史成绩都大于80分的同学f := filter(sg,func(s studentgrade) bool{if s.English > 80 && s.History > 80 {return true}return false})fmt.Println(f)
}

执行结果

[{pigff 1} {James 3}]

所以,这就是函数是编程带来的好处,只要满足一个函数模板,就可以给一个函数传多个功能不同的函数,完成不同的功能。

更多推荐

GO学习笔记——函数式编程(20)

本文发布于:2024-02-14 08:56:50,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1762925.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:函数   学习笔记

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!