slava项目(1):golang中type定义函数及其使用

slava是我参与的一个github开源项目,主要的工作是构建一个高性能、K-V云数据库。 slava项目的连接

在项目中定义了一个函数类型:

type Consumer func(key string, val interface{}) bool

然后在一个具体的函数中使用到了该函数类型,该ForEach函数传入的参数是一个上面所定义的函数类型:

// 遍历节点
func (dict *ConcurrentDict) ForEach(consumer Consumer) {
	if dict == nil {
		panic("dict is nil")
	}
	for _, s := range dict.table {
		s.mutex.RLock()
		for key, value := range s.m {
			b := consumer(key, value)
			if !b {
				break
			}
		}
		s.mutex.RUnlock()
	}
}

可能会让人疑惑不解的是,在ForEach函数中调用了consumer,也就是调用了我们定义的函数类型,但是函数类型的实现在哪实现了呢?

我们接着往下看,在接下来的Keys函数中调用了ForEach函数,如下:

func (dict *ConcurrentDict) Keys() []string {
	if dict == nil {
		panic("dict is nil")
	}
	i := 0
	keys := make([]string, dict.Len())
	dict.ForEach(func(key string, val interface{}) bool {
		if i < len(keys) {
			keys[i] = key
			i++
		} else {
			keys = append(keys, key)
		}
		return true
	})
	return keys
}

consumer的具体实现在这个函数中,在调用dict.ForEach的时候传入了一个函数的实现,这个函数的传参和返回值和最一开始定义的Consumer函数类型一样。并且ForEach函数的传参传入的时候我们定义的Consumer函数,所以上面的函数在调用dict.ForEach的时候实现了一个Consumer函数的实体。

1.在分析type定义函数类型的之前,我们先来了解一下什么是函数类型。

函数类型又叫函数签名 , 一个函数的类型就是函数定义首行去掉函数名、参数名和大括号,可以 使用 fmt.Printf 的”%T”格式化参数打印函数的类型。

package main

import "fmt"

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

func diff(a int, b int) int {
	return a - b
}

func printStr1(str string) {
	fmt.Println(str)
}

func printStr2(s string) {
	s2 := "abc"
	fmt.Println(s + s2)
}

func main() {
	fmt.Printf("%T\n", add)
	fmt.Printf("%T\n", diff)
	fmt.Println("--------------------")
	fmt.Printf("%T\n", printStr1)
	fmt.Printf("%T\n", printStr2)
}

打印函数类型

从上面的代码的运行结果可知,定义的add和diff属于同一种函数类型,而printStr1和printStr2属于另一种函数类型,函数的类型只和函数的传参类型、返回值类型以及他们的个数有关,和函数名以及函数的具体实现无关

2.type函数定义函数类型

在Go语言中type可以定义自定义的类型,比如type TreeNode struct {},type Name string ,也可以定义定义函数类型,比如 type fun func (a int) int ,这里自定义定义了一个叫fun的函数类型的变量,注意:fun是一个变量不是一个函数。既然是一个变量,那么相同底层类型的变量之间是可以相互转换的

(1)函数类型可以定义自己的函数

type handler func(a int, b int) int

func (h handler) AddIsTrue(x int) bool {
	a := x * 10
	b := x / 10
	return h(a, b) == x
}

(2)底层是相同类型可以相互转换

type handler func(a int, b int) int

func (h handler) AddIsTrue(x int) bool {
	a := x * 10
	b := x / 10
	return h(a, b) == x
}

func main() {
	// handler 和 add函数属于同一种类型
	var a handler = add
	a.AddIsTrue(10)
	// 
	var b handler = func(a int, b int) int {
		x := a * b
		return x
	}
}

在调用函数的时候传入函数的实现,与文章一开始中说的Keys函数调用ForEach函数的时候实现函数类型的情况类似

// 定义一个函数类型
type handler func(a int, b int) int

// 在该函数的传参中传入了函数类型变量
func fun(h handler, a int, b int) int {
	return h(a, b)
}

func main() {
	// 调用fun函数,并且在fun函数的传参中传入了和handler类型一样的函数
	c := fun(func(a int, b int) int {
		x := a / b
		return x
	}, 40, 20)
	fmt.Println(c)

	// 上面的代码可以改写成下面的代码
	//var h handler = func(a int, b int) int {
	//	x := a / b
	//	return x
	//}
	//c := fun(h, 40, 20)
	//fmt.Println(c)
}

3.总结

利用type字段可以自定义类型,定义出来的是一个变量,具有变量的性质,相同底层类型的变量之间是可以相互转换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值