文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么利用Golang泛型提高编码效率

2023-07-05 20:26

关注

本文小编为大家详细介绍“怎么利用Golang泛型提高编码效率”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么利用Golang泛型提高编码效率”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

工具函数

虽然标准库里面已经提供了大量的工具函数,但是这些工具函数都没有使用泛型实现,为了提高使用体验,我们可以使用泛型进行实现。

比如数值算法里很经典的math.Max()math.Min()都是float64类型的,但是很多时候我们使用的是intint64这些类型,在Golang引入泛型之前,我们经常像下面这样根据类型实现,产生大量模板代码:

func MaxInt(a, b int) int {if a > b {return a}return b}func MaxInt64(a, b int64) int64 {if a > b {return a}return b}// ...其他类型

而使用泛型则我们只需要一个实现:

func Max[T constraints.Ordered](a, b T) T {if a > b {return a}return b}

其中constraints.Ordered表示可排序类型,也就是可以使用三路运算符的类型[>, =, <],包含了所有数值类型和string。可以通过go get golang.org/x/exp引入。

代码地址

其他的像json解析、参数校验、slices等也可以通过泛型进行实现。

数据结构

Golang自带的泛型容器有slices和map,这两个数据结构其实可以完成大部分工作了,但是有时候我们可能还需要其他的数据结构,比如说优先级队列、链表等。

虽然Golang在container包下有heaplistring三个数据结构,但说实话使用起来不是很方便,特别是元素类型全是interface{},使用这些结构就需要各种类型转换。因此我们可以简单的拷贝这些代码,然后使用泛型进行改造,比如heap:

我们不但使用泛型进行实现,还把heap默认改为使用slice是实现,这样只需要实现一个LessFunc,而不是5个。

package heaptype LessFunc[T any] func(e1 T, e2 T) booltype Heap[T any] struct {h        []TlessFunc LessFunc[T]}func New[T any](h []T, lessFunc LessFunc[T]) *Heap[T] {heap := &Heap[T]{h:        h,lessFunc: lessFunc,}heap.init()return heap}// 移除堆顶元素func (h *Heap[T]) Pop() T {n := h.Len() - 1h.swap(0, n)h.down(0, n)return h.pop()}// 获取堆顶元素func (h *Heap[T]) Peek() T {return h.h[0]}// 添加元素到堆func (h *Heap[T]) Push(x T) {h.push(x)h.up(h.Len() - 1)}

代码地址

其他的数据结构还包括list、set、pqueue等。

模板代码

在后台业务代码里面,我们经常会有很多个业务处理函数,每个业务处理函数我们基本都会通过一些代码封装成一个HTTP接口,这里其实基本上都是模板代码,比如说对于一个使用gin实现的HTTP服务,每个接口我们都需要进行以下处理:

可以发现,参数绑定、处理响应几乎都是一样模板代码,鉴权也基本上是模板代码(当然有些鉴权可能比较复杂)。

因此我们可以编写一个泛型模板,把相同的部分抽取出来,用户只需要实现不同接口有差异的指定HTTP方法、URL和处理请求逻辑即可:

// 处理请求func do[Req any, Rsp any, Opt any](reqFunc ReqFunc[Req],serviceFunc ServiceFunc[Req, Rsp], serviceOptFunc ServiceOptFunc[Req, Rsp, Opt], opts ...Opt) gin.HandlerFunc {return func(c *gin.Context) {// 参数绑定req, err := BindJSON[Req](c)if err != nil {return}// 进一步处理请求结构体if reqFunc != nil {reqFunc(c, req)}var rsp *Rsp// 业务逻辑函数调用if serviceFunc != nil {rsp, err = serviceFunc(c, req)} else if serviceOptFunc != nil {rsp, err = serviceOptFunc(c, req, opts...)} else {panic("must set ServiceFunc or ServiceFuncOpt")}// 处理响应ProcessRsp(c, rsp, err)}}

这样,现在一个接口基本上只需要一行代码即可实现(不包括具体业务逻辑函数):

// 简单请求,不需要认证e.GET("/user/info/get", ginrest.Do(nil, GetUserInfo))// 认证,绑定UID,处理        reqFunc := func(c *gin.Context, req *UpdateUserInfoReq) {req.UID = GetUID(c)} // 这里拆多一步是为了显示第一个参数是ReqFunce.POST("/user/info/update", Verify, ginrest.Do(reqFunc, UpdateUserInfo))

代码地址,实现了一个基于gin的RESTful风格模板。

对象池/缓存

Golang标准库自带了一个线程安全、高性能、还能够根据对象热度自动进行释放的对象池sync.Pool,然而作为对象池,我们一般只会往里面放一种类型的对象,但sync.Pool里面的元素还是interface{}类型,因此我们可以简单的封装sync.Pool,让它里面的元素有具体类型:

这里其实就是简单的对象sync.Pool进行包装,然后添加了一个ClearFunc()在回收对象的时候进行一些清理操作,比如说byte切片我们需要让它的已用长度归零(容量还是不变)。

// 创建新对象type NewFunc[T any] func() T// 清理对象type ClearFunc[T any] func(T) Ttype Pool[T any] struct {p         sync.PoolclearFunc ClearFunc[T]}func New[T any](newFunc NewFunc[T], clearFunc ClearFunc[T]) *Pool[T] {if newFunc == nil {panic("must be provide NewFunc")}p := &Pool[T]{clearFunc: clearFunc,}p.p.New = func() any {return newFunc()}return p}// 获取对象func (p *Pool[T]) Get() T {return p.p.Get().(T)}// 归还对象func (p *Pool[T]) Put(t T) {if p.clearFunc != nil {t = p.clearFunc(t)}p.p.Put(t)}

作为字节数组对象池使用:

newFunc := func() []byte {return make([]byte, size, cap)}clearFunc := func(b []byte) []byte {return b[:0]}p := New(newFunc, clearFunc)bytes := p.Get() // 这里bytes类型是[]bytep.Put(bytes)

代码地址

对于缓存也是同理,目前大部分缓存库的实现都是基于interface{}或者是byte[],但是我们还是更加喜欢直接操作具体类型,因此我们可以自己使用泛型实现(或改造)一个缓存库。我自己也实现了一个泛型缓存策略库,里面包含LRU、LFU、ARC、NearlyLRU、TinyLFU等缓存策略。

读到这里,这篇“怎么利用Golang泛型提高编码效率”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯