Go——函数类型

函数类型

使用func FunctionName()语法格式定义的函数我们称为“有名函数”,这里所谓的有名是指函数在定义时指定了“函数名”;与之对应的是“匿名函数”,所谓的匿名函数就是在定义时使用func()语法格式,没有指定函数名。通常所说的函
数就是指“有名函数”。

函数类型也分两种,一种是函数字面量类型(未命名类型),另一种是函数命名类型。

函数字面量类型

函数字面量类型的语法表达格式是func (InputTypeList) OutputTypeList,可以看出“有名函数”和“匿名函数”的类型都属于函数字面量类型。有名函数的定义相当于初始化一
个函数字面量类型后将其赋值给一个函数名变量;“匿名函数”的定义也是直接初始化一个函数字面量类型,只是没有绑定到一个具体变量上。从Go类型系统的角度来看,“有名函数”和“匿名函数”都是函数字面量类型的实例。

函数命名类型

使用type NewType 0ldType语法定义一种新类型,这种类型都是命名类型,同理可以使用该方法定义一种新类型:函数命名类型,简称函数类型。例如:
``go
type NewFuncType FuncLiteral

依据Go语言类型系统的概念,NewFuncType为新定义的函数命名类型,FuncLiteral为函数字面量类型,FuncLiteral为函数类型NewFuncType的底层类型。当然也可以使用type在一个函数类型中再定义一个新的函数类型,这种用法在语法上是允许的,但很少这么使用。例如:
```go
type NewFuncType oldFuncType
函数声明

Go语言没有C语言中函数声明的语义,准确地说,Go代码调用G0编写的函数不需要声明,可以直接调用,但Go调用汇编语言编写的函数还是要使用函数声明语句,示例如下。

//函数声明=函数名+函数签名
//函数签名
func (InputTypeList) OutputTypeList
//函数声明
func FuncName (InputTypeList) OutputTypeList

下面通过一个具体的示例来说明上述概念。

package main

import "fmt"

func main() {
	f := func(a, b int) int {
		return a + b
	}

	g(1, 2)
	f(1, 2)

	//f和add的函数签名相同
	fmt.Printf("%T\n", f)//func(int, int) int
	fmt.Printf("%T\n", add)//func(int, int) int
}

//有名函数定义,函数名是add
//add类型是函数字面量类型 func (int, int) int
func add(a, b int) int {
	return a + b
}

//函数声明语句,用于Go代码调用汇编代码
//func add(int, int) int

//add函数的签名,实际上就是add的字面量类型
//func (int, int) int

//匿名函数不能独立存在,常作为函数参数、返回值,或者赋值给某个变量
//匿名函数可以直接显式初始化
//匿名函数的类型也是函数字面量类型func (int, int) int
//func (a, b int) int {
//	return a + b
//}

//新定义函数类型ADD
//ADD底层类型是函数字面量类型 func (int, int) int
type ADD func(int, int) int

//add和ADD的底层类型相同,并且add是字面量类型
//所以add可以直接赋值给ADD类型的变量
var g ADD = add

前面谈到字面量类型是一种未命名类型(unnamed type),其不能定义自己的方法,所以必须显式地使用tye声明一个有名函数类型,然后为其添加方法。通常说的函数类型就是指有名函数类型,“函数签名”是指函数的字面量类型,在很多地方把函数类型和函数签名等价使用,这是不严谨的。由类型转换的规则可知:这两种类型的底层类型相同,并且其中一个是字面量类型,二者是可以相互转换的。下面来看一下经典的http标准库对函数类型的实现,进一步理解这种用法。

//src/net/http/server.go

//定义一个有名函数类型HandlerFunc
type HandlerFunc func(ResponseWriter, *Request)

//为有名函数类型添加方法,属于一种装饰器方法
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

//函数类型HandlerFunc实现了接口Handler的方法
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

func (mux *ServeMux) Handle(pattern string, handler Handler)

//所以HandlerFunc类型的变量可以传递给Handler接口变量
func(mux *ServeMux) HandlerFunc(pattern string, handler func(ResponseWriter, *Request)){
	mux.Handler(pattern, HandlerFunc(handler))
}

通过hp标准库里面对于函数类型的使用,我们可以看到函数类型的如下意义:

  1. 函数也是一种类型,可以在函数字面量类型的基础上定义一种命名函数类型。
  2. 有名函数和匿名函数的函数签名与命名函数类型的底层类型相同,它们之间可以进行类型转换。
  3. 可以为有名函数类型添加方法,这种为一个函数类型添加方法的技法非常有价值,可以方便地为一个函数增加“拦截”或“过滤”等额外功能,这提供了一种装饰设计模式。
  4. 为有名函数类型添加方法,使其与接口打通关系,使用接口的地方可以传递函数类型的变量,这为函数到接口的转换开启了大门。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值