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

相关文章

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是

Python中@classmethod和@staticmethod的区别

《Python中@classmethod和@staticmethod的区别》本文主要介绍了Python中@classmethod和@staticmethod的区别,文中通过示例代码介绍的非常详细,对大... 目录1.@classmethod2.@staticmethod3.例子1.@classmethod

Golan中 new() 、 make() 和简短声明符的区别和使用

《Golan中new()、make()和简短声明符的区别和使用》Go语言中的new()、make()和简短声明符的区别和使用,new()用于分配内存并返回指针,make()用于初始化切片、映射... 详细介绍golang的new() 、 make() 和简短声明符的区别和使用。文章目录 `new()`

Python中json文件和jsonl文件的区别小结

《Python中json文件和jsonl文件的区别小结》本文主要介绍了JSON和JSONL两种文件格式的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下... 众所周知,jsON 文件是使用php JSON(JavaScripythonpt Object No

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

Golang使用etcd构建分布式锁的示例分享

《Golang使用etcd构建分布式锁的示例分享》在本教程中,我们将学习如何使用Go和etcd构建分布式锁系统,分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要,它有助于维护一致性,防止竞... 目录引言环境准备新建Go项目实现加锁和解锁功能测试分布式锁重构实现失败重试总结引言我们将使用Go作

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一