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

本文主要是介绍golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • http.Handle和http.HandleFunc的区别
  • http.Handle分析
    • type func巧妙运用
  • http.HandleFunc分析
  • 总结
  • 参考资料

http.Handle和http.HandleFunc的区别

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

下面代码启动了一个 http 服务器,监听 8080 端口,并注册路由。实现这两个路由注册的方法有点不同,一个使用 http.Handle,另一个使用 http.HandleFunc ,下面来看看这两个之间的区别;
在这里插入图片描述

http.Handle分析

我们简单看一下http.Handle函数
在这里插入图片描述
这个 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 mainimport "fmt"type Sayer interface {say()
} type dog int// dog实现了Sayer接口
func (d dog) say() {fmt.Println("汪汪汪")
}func main() {var d dogd.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 mainimport "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() 用法分析

这篇关于golang学习笔记——http.Handle和http.HandleFunc的区别与type func巧妙运用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/633411

相关文章

go 指针接收者和值接收者的区别小结

《go指针接收者和值接收者的区别小结》在Go语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的

售价599元起! 华为路由器X1/Pro发布 配置与区别一览

《售价599元起!华为路由器X1/Pro发布配置与区别一览》华为路由器X1/Pro发布,有朋友留言问华为路由X1和X1Pro怎么选择,关于这个问题,本期图文将对这二款路由器做了期参数对比,大家看... 华为路由 X1 系列已经正式发布并开启预售,将在 4 月 25 日 10:08 正式开售,两款产品分别为华

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法

《golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法》:本文主要介绍golang获取当前时间、时间戳和时间字符串及它们之间的相互转换,本文通过实例代码给大家介绍的非常详细,感兴趣... 目录1、获取当前时间2、获取当前时间戳3、获取当前时间的字符串格式4、它们之间的相互转化上篇文章给大家介

Nginx中配置HTTP/2协议的详细指南

《Nginx中配置HTTP/2协议的详细指南》HTTP/2是HTTP协议的下一代版本,旨在提高性能、减少延迟并优化现代网络环境中的通信效率,本文将为大家介绍Nginx配置HTTP/2协议想详细步骤,需... 目录一、HTTP/2 协议概述1.HTTP/22. HTTP/2 的核心特性3. HTTP/2 的优

使用Python自建轻量级的HTTP调试工具

《使用Python自建轻量级的HTTP调试工具》这篇文章主要为大家详细介绍了如何使用Python自建一个轻量级的HTTP调试工具,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录一、为什么需要自建工具二、核心功能设计三、技术选型四、分步实现五、进阶优化技巧六、使用示例七、性能对比八、扩展方向建

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

CSS Padding 和 Margin 区别全解析

《CSSPadding和Margin区别全解析》CSS中的padding和margin是两个非常基础且重要的属性,它们用于控制元素周围的空白区域,本文将详细介绍padding和... 目录css Padding 和 Margin 全解析1. Padding: 内边距2. Margin: 外边距3. Padd

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.