golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用

这篇具有很好参考价值的文章主要介绍了golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

http.Handle和http.HandleFunc的区别

http.Handle和http.HandleFunc的区别体现了Go语言接口的巧妙运用

下面代码启动了一个 http 服务器,监听 8080 端口,并注册路由。实现这两个路由注册的方法有点不同,一个使用 http.Handle,另一个使用 http.HandleFunc ,下面来看看这两个之间的区别;
golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用,golang从入门到入门,golang,学习,笔记

http.Handle分析

我们简单看一下http.Handle函数
golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用,golang从入门到入门,golang,学习,笔记
这个 Handler 类型是什么呢,其实它就是一个接口,包含一个 ServeHttp() 的方法:

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

在Go语言常规代码中,接口一般是这样用的

// Sayer 接口
type Sayer interface {
    say()
} 

type dog struct {}

type cat struct {} 

// dog实现了Sayer接口
func (d dog) say() {
    fmt.Println("汪汪汪")
}

// cat实现了Sayer接口
func (c cat) say() {
    fmt.Println("喵喵喵")
} 

先写一个接口,再写一个结构体,最后将结构体与方法相关联,也就是这个结构体类型dog实现了接口。

其实type关键字作用是声明类型,这里应该写为dog类型实现Sayer接口,cat类型实现Sayer接口,比较合适。(一个对象只要全部实现了接口中的方法,那么就实现了这个接口。)

我们再看一个例子

package main

import "fmt"

type Sayer interface {
    say()
} 

type dog int

// dog实现了Sayer接口
func (d dog) say() {
    fmt.Println("汪汪汪")
}

func main() {
   var d dog
   d.say()
}

没错,我们把int类型重新定义为一个新的类型,这个类型叫dogdog这个类型也实现了Sayer接口。所以,玩转一个接口一般分为三步:

  • 第一步定义一个接口类型,
  • 第二步定义一个非接口类型
  • 第三步在非接口类型上实现接口。

所以,第二步的代码只要定义一个非接口类型即可。

type func巧妙运用

我们知道,func也是一种类型,那可以试着用func类型实现接口。

type Sayer interface {
    say(str string)
} 

type Dog func(string)

func (f Dog) say(str string) {
	f(str)
}

代码写到IDE上也没有报错,说明这段代码是可行的。代码中的f(str)又是什么意思。f(str)看起来有点像一个名叫f的函数,传入了一个str的参数,当方法被调用时(注意,Go语言中方法与函数的区别),这个函数就行执行,只不过这个函数的类型是Dog类型。等等,有点不对。这个函数就行执行,执行了什么?所以,执行之前一定要有一个Dog类型的实例。可以是一个有名称的函数,也可以是一个匿名函数,

package main

import "fmt"

type Sayer interface {
    say(str string)
} 

type Dog func(string)

func (f Dog) say(str string) {
	f(str)
}

func main() {
	d := Dog(func(str string){
		fmt.Println("转换类型")
	})
	
	d("开始执行")
}

特别要注意的是这段代码中的Dog(func(str string)表示是一个强制转换,把匿名函数转为Dog类型。理解了type func,再看方法二也就不难了。

http.HandleFunc分析

从代码上看函数二比函数一少定义了一个结构体,简洁一些,写起来也方便一些。那为什么函数二比函数一少写了一个结构体? 下面看代码

func HandleFunc(pattern string,
	handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

通过源码得知HandleFunc是http包下的一个大写字母开头的公开函数,该函数接收两个参数,一个是路由匹配的字符串,另外一个是 func(ResponseWriter, *Request) 类型的函数。

然后继续调用 DefaultServeMux.HandleFunc(pattern, handler)

func (mux *ServeMux) HandleFunc(pattern string,
	handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}

可以看到,代码中的第6行,HandlerFunc(handler),HandlerFunc可不是一个函数,而是类型转换

Go语言中只有强制类型转换,没有隐式类型转换。下面的语法只能在两个类型之间支持相互转换的时候使用。

  • 强制类型转换的基本语法如下:
    T(表达式)
    
    其中,T表示要转换的类型。表达式包括变量、复杂算子和函数返回值等。

这里是把 handler 转换成了 HandlerFunc 类型,而 HandlerFunc 类型则如下所示:

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

该类型实现了 Handler 接口(因为该类型有一个ServeHTTP方法),所以其也可以转换成 Handler 类型,接下来调用 mux.Handle(pattern string, handler Handler) 就跟 http.Handle 的流程是一样的了。

	Handler接口   --->	HandlerFunc类型
					  ︿ 		\
					 /	         \
					/	          ﹀
匿名函数   --->   强制转换       HandlerFunc类型的ServeHTTP方法调用HandlerFunc类型的函数      

总结

http.Handle的使用方法和面向对象编程差不多,第一步定义一个接口类型,第二步定义一个非接口类型,第三步在非接口类型上实现接口。

http.HandleFunc使用上简洁一些,但原理比较复杂。先定义一个函数(参数类型,返回值都要和ServeHTTP一样),再将它强转为HandlerFunc类型,HandlerFunc类型有一个方法叫ServeHTTP,这方法会执行一个名叫f的函数,这个函数的类型就是HandlerFunc。因为一个对象只要全部实现了接口中的方法,那么就实现了这个接口。所以,HandlerFunc类型实现了type Handler interface这个接口。所以,我们只要写一个匿名函数,内部就会为我们转为HandlerFunc类型。

参考资料

理解go的function types
golang中 type func() 用法分析文章来源地址https://www.toymoban.com/news/detail-815181.html

到了这里,关于golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • TypeError: Cannot handle this data type: (1, 1, 3), <f8和Image.fromarray()函数转换后图像失真

    TypeError: Cannot handle this data type: (1, 1, 3), <f8和Image.fromarray()函数转换后图像失真

    错误显示1. 错误显示2. (预测为RGB图像,结果失真为黑色) 原因: 采用 matplotlib.image 读入图片数组,注意这里读入的数组是 float32 型的,范围是 0-1,而 PIL.Image 数据是 uinit8 型的,范围是0-255 (可根据 python PIL图像处理 - jujua - 博客园 (cnblogs.com) 分析) 更改方案: image=Image

    2024年02月12日
    浏览(29)
  • You may need an appropriate loader to handle this file type, currently no loaders are configured to

    You may need an appropriate loader to handle this file type, currently no loaders are configured to

    代码从git仓库拉的最新代码,下载node_module依赖包无法运行,以前已经下载的依赖包可以运行。 原因: “@vueuse/head”: “^0.7.5”, 指的是 version 与version兼容 ,与2.3.1版本兼容,相当于2.X.X, 即=2.3.1 3.0.0,不改变大版本号。 也就是说看着是0.7.5,但是有更新的话就会下载 大于0.7

    2024年02月10日
    浏览(12)
  • 【Nginx13】Nginx学习:HTTP核心模块(十)Types、AIO及其它配置

    【Nginx13】Nginx学习:HTTP核心模块(十)Types、AIO及其它配置

    今天学习的内容也比较简单,主要的是 Types 相关的配置,另外还会了解一下 AIO 以及部分没有特别大的分类归属的配置指令的使用。后面的内容都是 HTTP 核心模块中比较小或者比较简单的部分了。有很多配置项其实我们平常并不常用,甚至很多在学习之前我都不知道有它们的

    2024年02月12日
    浏览(14)
  • typing python 类型标注学习笔记

    typing python 类型标注学习笔记

    在Python 3.5版本后引入的typing模块为Python的静态类型注解提供了支持。这个模块在增强代码可读性和维护性方面提供了帮助。 typing 模块为Python带来了类型提示和类型检查的能力。它允许开发者在代码中添加类型注解,提高代码的可读性和可维护性。尽管Python是一种动态类型语

    2024年01月21日
    浏览(10)
  • Linux shell编程学习笔记33:type 命令

    Linux shell编程学习笔记33:type 命令

     目录 0 引言 1 type 命令的功能和格式 1.1 type命令的功能 1.2 type 命令的格式 2 type命令用法实例 2.1用type命令查看shell内置命令(以echo命令为例) 2.2 用type命令查看别名(以ls命令为例) 2.3 用type命令同时查看shell内置命令和别名(以echo和ls命令为例) 2.4 用type命令查看外部

    2024年02月03日
    浏览(11)
  • Golang快速入门到实践学习笔记

    Golang快速入门到实践学习笔记

    Go程序设计的一些规则 Go之所以会那么简洁,是因为它有一些默认的行为: 大写字母开头的变量是可导出的,也就是其它包可以读取 的,是公用变量;小写字母开头的就是不可导出的,是私有变量。 大写字母开头的函数也是一样,相当于class 中的带public的公有函数;

    2024年02月20日
    浏览(8)
  • 【后端学习笔记·Golang】邮箱邮件验证

    流程: 接收用户请求后生成随机验证码,并将验证码存入Redis中,并设置TTL 通过gomail发送验证码给用户邮箱 接收用户输入的验证码,与Redis中存放的验证码进行比对 ​ 随机种子通过 time.Now().UnixNano() 进行设置,以确保对于同一个用户每次请求都使用不同的种子。然后,定义

    2024年04月26日
    浏览(19)
  • golang学习笔记(defer基础知识)

    golang学习笔记(defer基础知识)

    defer语句用于golang程序中延迟函数的调用, 每次defer都会把一个函数压入栈中, 函数返回前再把延迟的函数取出并执行。 为了方便描述, 我们把创建defer的函数称为主函数, defer语句后面的函数称为延迟函数。延迟函数可能有输入参数, 这些参数可能来源于定义defer的函数,

    2024年04月25日
    浏览(10)
  • Golang 中高级工程师学习笔记

    闭包(Closure)是一种函数值,它可以引用在其外部定义的变量。闭包允许这些变量保持在函数内部,而不是被每次调用时重新创建。闭包的作用主要体现在以下几个方面 封装: 闭包允许函数访问其外部作用域中的变量,形成了一种封装。这意味着可以在闭包内部定义私有的

    2024年01月21日
    浏览(11)
  • Golang学习笔记_RabbitMQ的原理架构和使用

    实现了高级消息队列协议(Advanced Message Queuing Protcol)AMQP 消息队列中间件的作用(Redis实现MQ里面有写过,这里简单带过) 解耦 削峰 异步处理 缓存 消息通信 提高扩展性 RabbitMQ 架构理解 binding(绑定):交换机将消息路由给Queue所遵循的规则,可以定义一个路由键,用于交换机

    2024年04月24日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包