golang中函数类型
今天看Martini文档,其功能列表提到完全兼容http.HandlerFunc接口,就去查阅了Go: net/http的文档,看到type HandlerFunc这部分,顿时蒙圈了。由于之前学习的时候没有关注过function types的知识点,就Google了一些文章,才算是有了个大概的了解。
从golang的官方文档得知function types的解释是这样的。
A function type denotes the set of all functions with the same parameter and result types.
先找个例子来看一下:
package main import "fmt" // Greeting function types
type Greeting func(name string) string func say(g Greeting, n string) {
fmt.Println(g(n))
} func english(name string) string {
return "Hello, " + name
} func main() {
say(english, "World")
}
输出Hello, World
say()函数要求传入一个Greeting类型,因为english函数的参数和返回值跟Greeting一样,参考接口的概念这里可以做类型转换。我们换个方式来实现上面的功能:
package main import "fmt" // Greeting function types
type Greeting func(name string) string func (g Greeting) say(n string) {
fmt.Println(g(n))
} func english(name string) string {
return "Hello, " + name
} func main() {
g := Greeting(english)
g.say("World")
}
同样输出Hello, World,只是给Greeting类型添加了say()方法。上面说了,函数类型是表示所有包含相同参数和返回类型的函数集合。我们在一开始先把func(name string) string这样的函数声明成Greeting类型,接着我们通过Greeting(english)将english函数转换成Greeting类型。通过这个转换以后,我们就可以借由变量g调用Greeting类型的say()方法。两段代码的差异就是go的类型系统添加方法和类C++语言添加类型方法的差异,具体讲解可以去查看《Go语言编程》第3章为类型添加方法这一节。
既然是函数集合,那么只有一个函数显然是不足以说明问题的。
package main import "fmt" // Greeting function types
type Greeting func(name string) string func (g Greeting) say(n string) {
fmt.Println(g(n))
} func english(name string) string {
return "Hello, " + name
} func french(name string) string {
return "Bonjour, " + name
} func main() {
g := Greeting(english)
g.say("World")
g = Greeting(french)
g.say("World")
}
输出 Hello, World
Bonjour, World
在其他语言里面,有些函数可以直接作为参数传递,有些是以函数指针进行传递,但是都没有办法像go这样可以给函数类型“增加”新方法。
回到Go: net/http的HandlerFunc类型,只要Martini的函数遵循文档中type HandlerFunc func(ResponseWriter, *Request)的要求,就可以转换成HandlerFunc类型,也就可以调用func (HandlerFunc)ServeHTTP函数。
在 Go 语言中,我们可以把函数作为一种变量,用 type 去定义它,那么这个函数类型就可以作为值传递,甚至可以实现方法,这一特性是在太灵活了,有时候我们甚至可以利用这一特性进行类型转换。作为值传递的条件是类型具有相同的参数以及相同的返回值。
函数的类型转换 Go 语言的类型转换基本格式如下: type_name(expression)
复制代码 举个例子: package main import "fmt" type CalculateType func(int, int) // 声明了一个函数类型 // 该函数类型实现了一个方法
func (c *CalculateType) Serve() {
fmt.Println("我是一个函数类型")
} // 加法函数
func add(a, b int) {
fmt.Println(a + b)
} // 乘法函数
func mul(a, b int) {
fmt.Println(a * b)
} func main() {
a := CalculateType(add) // 将add函数强制转换成CalculateType类型
b := CalculateType(mul) // 将mul函数强制转换成CalculateType类型
a(2, 3)
b(2, 3)
a.Serve()
b.Serve()
} // 5
// 6
// 我是一个函数类型
// 我是一个函数类型
复制代码 如上,声明了一个 CalculateType 函数类型,并实现 Serve() 方法,并将拥有相同参数的 add 和 mul 强制转换成 CalculateType 函数类型,同时这两个函数都拥有了 CalculateType 函数类型的 Serve() 方法。
函数作参数传递 package main import "fmt" type CalculateType func(a, b int) int // 声明了一个函数类型 // 加法函数
func add(a, b int) int {
return a + b
} // 乘法函数
func mul(a, b int) int {
return a * b
} func Calculate(a, b int, f CalculateType) int {
return f(a, b)
} func main() {
a, b := 2, 3
fmt.Println(Calculate(a, b, add))
fmt.Println(Calculate(a, b, mul))
}
// 5
// 6
复制代码 如上例子,Calculate 的 f 参数类型为 CalculateType,add 和 mul 函数具有和 CalculateType 函数类型相同的参数和返回值,因此可以将 add 和 mul 函数作为参数传入 Calculate 函数中。
net/http 包源码例子 // HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
复制代码 // HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
复制代码 type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
复制代码 刚开始看到这段源码的时候,真的有点懵逼了,这段源码的目的是为了将我们的 Handler 强制实现 ServeHTTP() 方法,如下例子: func sayHi(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hi")
} func main() {
http.HandlerFunc("/", sayHi)
http.ListenAndserve(":8080", nil)
}
复制代码 因为 HandlerFunc 是一个函数类型,而 sayHi 函数拥有和 HandlerFunc 函数类型一样的参数值,因此可以将 sayHi 强制转换成 HandlerFunc,因此 sayHi 也拥有了 ServeHTTP() 方法,也就实现了 Handler 接口,同时,HandlerFunc 的 ServeHTTP 方法执行了它自己本身,也就是 sayHi 函数,这也就可以看出来了,sayHi 就是 Handler 被调用之后的执行结果。
golang中函数类型的更多相关文章
- golang中值类型/指针类型的变量区别总结
转自:https://segmentfault.com/a/1190000012329213 值类型的变量和指针类型的变量 先声明一个结构体: type T struct { Name string ...
- golang中基本类型存储大小和转换
Go语言的基本类型有: bool string int.int8.int16.int32.int64 uint.uint8.uint16.uint32.uint64.uintptr byte // u ...
- golang中函数的可变参数
package main import "fmt" // 一个函数中最多只可有一个可变参数, 如果参数列表中还有其它类型的参数,则可变参数写在最后 // 注意:参数不定,参数的个数 ...
- golang中值类型的嵌入式字段和指针类型的嵌入式字段
总结: 1. 值类型的嵌入式字段,该类型拥有值类型的方法集,没有值指针类型的方法集 2. 指针类型的嵌入式字段,该类型拥有值指针类型的方法集,没有值类型的方法集,并且,该类型的指针类型也有值指针类型的 ...
- golang中函数的参数
1. 函数当做函数的参数 package main import "fmt" type HandleFunc func(int) (int, bool) func add10(nu ...
- golang中接口类型小案例
1. 在项目中实现注册成功之后,向用户发送邮件.微信提醒 package main import "fmt" type IMessage interface { send() b ...
- golang的函数
在golang中, 函数是第一类值(first-class object), 即函数可以赋值与被赋值. 换言之, 函数也可以作为ReceiverType, 定义自己的method. 实例: http. ...
- 说说不知道的Golang中参数传递
本文由云+社区发表 导言 几乎每一个C++开发人员,都被面试过有关于函数参数是值传递还是引用传递的问题,其实不止于C++,任何一个语言中,我们都需要关心函数在参数传递时的行为.在golang中存在着m ...
- Swift2.0语言教程之函数的返回值与函数类型
Swift2.0语言教程之函数的返回值与函数类型 Swift2.0中函数的返回值 根据是否具有返回值,函数可以分为无返回值函数和有返回值函数.以下将会对这两种函数类型进行讲解. Swift2.0中具有 ...
随机推荐
- 简介、变量、常数、if、基础数据类型、注释、input()
### 1.python的历史 python2和python3的区别 python2 源码不统一,重复代码 python 源码统一,没有重复代码 2004 Django框架的诞生 2.python ...
- Codeforces Round #479 (Div. 3) 题解 977A 977B 977C 977D 977E 977F
A. Wrong Subtraction 题目大意: 定义一种运算,让你去模拟 题解: 模拟 #include <iostream> #include <cstdio> ...
- 使用node.js实现反向代理
一. 反向代理的应用场景 1. 静态资源与动态资源分离 e.g. 图片服务器 2. AJAX跨域访问 3. 搭建统一服务网关接口 二. 使用node.js实现反向代理 1. 安装http-proxy模 ...
- php中$_REQUEST、 $_GET、 $_POST、 $_COOKIE 的关系和区别
看到REQUEST可以通吃GET .POST .COOKIE 后 感觉这个$_REQUEST太强大了是不是其他的几个超级变量就没有用了,下面对他们整体做个比较: 1.安全性 post>get 2 ...
- day 42 02--CSS的继承性和层叠性
02--CSS的继承性和层叠性 本节目录 一 继承性 二 层叠性 三 层叠性权重相同处理 一 继承性 css有两大特性:继承性和层叠性 面向对象语言都会存在继承的概念,在面向对象语言中,继承的特点 ...
- centos部署jeecms
首先下载安装包apache-tomcat-8.5.40.tar.gz jdk-8u211-linux-x641.rpm jeecmsv9.war 已经在WEB-INF/config/jdbc.prop ...
- 06_Spring JDBCTemplate
Spring对不同持久化技术的支持 ORM持久化技术 模板类 JDBC org.springframework.jdbc.core.JdbcTemplate Hibernate3.0 org.spri ...
- java基础之DateFormat类
DateFormat DateFormat类概述 DateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间. 是抽象类,所以使用其子类SimpleDateFor ...
- <每日一题>题目20:简单python练习题(11-20)
#11.编写程序,输入一个自然数,输出它的二进制.八进制.十六进制表示形式 Num = input("请输入任性自然数:") Num = eval(Num) print(" ...
- springmvc-@RequestBody无法映射首字母大写的属性
@RequestBody可以将前台传入的json格式数据自动映射成对象,当如果属性的首字母大写,则会出现不能映射的情况,如: private String ICCID;会出现映射失败的情况 解决办法: ...