国产化驱动经济自主性与科技创新的未来之路
895
2022-11-30
Go 函数 函数类型和作为函数返回值
函数也是一种类型,定义变量用var,定义常量用const,定义函数用func。
匿名函数
匿名函数,没有名字,可以在定义的时候就直接运行了。
什么场景下会使用匿名函数呢?也就是闭包。一个最常用的场景就是程序运行出现错误的时候,我们要去恢复,一般是通过关键字defer,我们要有一个程序逻辑,在某些特定场景下运行的,但是我没有必要为整个逻辑定义函数,通常这样就可以使用闭包来做。
闭包
闭包(Closure)是引用了自由变量的函数,自由变量将和函数一同存在,即使已经离开了创造它的环境,闭包复制的是原对象的指针。
通常情况下一个函数的内部变量,在函数退出之后,这个函数的局部变量都会标志以废弃,都会被垃圾回收机制给回收,但是闭包就不一样。
package mainimport "fmt"//闭包(Closure)是引用了自由变量的函数。自由变量将和函数一同存在,即使已经离开了创造它的环境。func sub() func() { i := 10 fmt.Printf("%p\n", &i) b := func() { fmt.Printf("i addr %p\n", &i) //闭包复制的是原对象的指针 i-- //b函数内部引用了变量i fmt.Println(i) } return b //返回了b函数,变量i和b函数将一起存在,即使已经离开函数sub()}// 外部引用函数参数局部变量func add(base int) func(int) int { return func(i int) int { fmt.Printf("base addr %p\n", &base) base += i return base }}func main() { b := sub() b() b() fmt.Println() tmp1 := add(10) fmt.Println(tmp1(1), tmp1(2)) //11,13 // 此时tmp1和tmp2不是一个实体了 tmp2 := add(100) fmt.Println(tmp2(1), tmp2(2)) //101,103}
函数也是一种数据类型
函数类型
函数也可以赋值给变量,存储在数组、切片、映射中,也可作为参数传递给函数或作为函数返回值进行返回。
func add(a,b int) int{ return a + b}func main() { c := add fmt.Printf("%v",reflect.TypeOf(c))}
这个c到底是什么东西?可以打印一下c的类型。
func(int, int) int 通过这个也可以看出来函数也是一种类型即函数类型,函数类型由参数类型和数量以及返回值数量和类型组成的。
如果我想要定义一个函数类型的变量怎么定义呢?
var f func(int,int) int
这样就定义了一个函数类型,变量后面就是函数类型。
var f func(int,int) intf =addfmt.Println(f(2,3))
func add(a,b int) int{ return a + b}func mul(a,b int) int{ return a - b}func main() { c := add fmt.Printf("%v",reflect.TypeOf(c)) fs := []func(int,int) int{c,mul} fmt.Println(fs) for _,v := range fs{ fmt.Println(v(2,1)) }}
可以看到函数也是一种类型。函数类型是一个可以将函数类型赋值给一个变量。
通过函数类型也可以定义集合类型,如切片,map。
在 Go 语言中,函数类型、map 类型自身,以及切片只支持与 nil 的比较,而不支持同类型两个变量的比较。
s1 := make([]int, 1)s2 := make([]int, 2)f1 := func() {}f2 := func() {}m1 := make(map[int]string)m2 := make(map[int]string)println(s1 == s2) // 错误:invalid operation: s1 == s2 (slice can only be compared to nil)println(f1 == f2) // 错误:invalid operation: f1 == f2 (func can only be compared to nil)println(m1 == m2) // 错误:invalid operation: m1 == m2 (map can only be compared to nil)
回调函数(Callback)
func print1(fmt1 func(string)string,args ...string){ for i,v := range args{ fmt.Println(i,fmt1(v)) }}func format(params string)string{ return "*" + params + "*"}func table(params string)string{ return "|" + params + "|"}func main() { names := []string{"jack","lucas"} print1(format,names...) print1(table,names...)}
定义的函数format可以作为参数传入到print1函数里面去。print1函数可以接收任意函数类型为func(string)string的函数。上面就是通过函数类将一个函数传入到另外一个函数里面去了。
函数类型在定义的时候,一定要定义出它的参数和返回值。
函数返回值为函数类型
func()是一个是没有参数,没有返回值的一个函数
func sayHello() { fmt.Println("hello")}func sayHi() { fmt.Println("hi")}func genFunc() func(){ rand.Seed(time.Now().Unix()) if rand.Int() % 2 == 0 { return sayHello }else { return sayHi }}func main() { a := genFunc() a()}
所以函数可以放到切片里面,map里面,可以赋值给一个变量,可以作为参数传递,也可以作为函数值进行返回。
这里FiledsFunc(s string,f func(rune) bool)[]string,这里第一个参数是string类型的,第二个参数是一个函数,一个传递rune类型返回值是bool类型的函数。
FiledsFunc(s string,f func(rune) bool)[]string
func aFileds(split rune) bool { return split == 'a'} c := strings.FieldsFunc("abcd",aFileds) fmt.Println(c)
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~