当前位置:
首页
文章
前端
详情

深入JavaScript高级语法-coderwhy大神

深入JavaScript高级语法-coderwhy大神

Golang泛型提高了编码效率

  • 前言 * Golang的泛型已经出来一段时间了,大家应该对它有所了解,甚至在应用中使用过。虽然Golang的泛型功能简单,而且可能会增加代码的复杂度,但是过度使用也可能会降低代码的可读性。 但不可否认的是,泛型确实使我们在使用Golang时能够提取一些常用代码,避免代码的重复拷贝,提高代码性能(避免类型转换),提高编码效率和体验,提高代码可维护性。 本文主要介绍我用Golang泛型做了什么。
  • 工具功能 * 虽然标准库中已经提供了大量的工具函数,但是这些工具函数并不是由泛型实现的。为了改善体验,我们可以通过泛型来实现它们。 比如经典的数学。Max(),数学。数值算法中的Min()是float64类型,但是很多时候我们使用这些类型` int,int64 '。在Golang引入泛型之前,我们经常按照如下类型来实现它们,从而产生了大量的模板代码:
    func MaxInt(a,b int) int {
    如果a > b {
    返回a
    }
    返回b
    }
    

func MaxInt64(a,b int64) int64 { 如果a > b { 返回a } 返回b }

//...其他类型

复制代码
使用泛型时,我们只需要一个实现:

func MaxT约束。有序 T { 如果a > b { 返回a } 返回b }

复制代码
约束在哪里。Ordered表示可排序的类型,即可以使用三向运算符[>,=,
代码地址
其他如json解析、参数检查、切片等。也可以通过泛型实现。
# # # # * *数据结构* *
Golang自己的通用容器是切片和地图。这两种数据结构实际上可以完成大部分工作,但有时我们可能需要其他数据结构,比如优先级队列和链表。
虽然Golang在容器的‘包’下有堆、列表、环三种数据结构,但是用起来说实话不是很方便,尤其是元素类型都是‘接口{ }’。使用这些结构需要各种类型的转换。所以我们可以简单地复制这些代码,然后用泛型对它们进行转换,比如heap:
我们不仅使用泛型来实现,还默认将heap改为slice来实现,所以我们只需要实现一个LessFunc而不是五个。

包堆

类型LessFunc[T any] func(e1 T,e2 T) bool

类型堆[T any]结构{ h []T lessFunc }

func New[T any](h []T,lessFunc LessFunc[T]) *Heap[T] { 堆:= &Heap[T]{ h: h, lessFunc: lessFunc, } heap.init() 返回堆 }

//移除堆顶部元素 func (h *Heap[T]) Pop() T { n := h.Len() - 1 h.swap(0,n) h.down(0,n) return h.pop() }

//获取堆顶部元素 func (h *Heap[T]) Peek() T { 返回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
证明
参数绑定
处理请求
处理

可以发现参数绑定和处理响应几乎都是同一个模板代码,认证基本都是模板代码(当然有些认证可能比较复杂)。
因此,我们可以编写一个通用模板,并提取相同的部分。用户只需要用不同的接口实现指定的HTTP方法、URL和请求处理逻辑:

//处理请求 func do[Req any,Rsp any,Opt any](reqFunc ReqFunc[Req]), serviceFunc ServiceFunc[Req,Rsp],serviceopttfunc serviceopttfunc[Req,Rsp,Opt],opts...Opt)杜松子酒。HandlerFunc { 返回函数(c *gin。上下文){ //参数绑定 req,err := BindJSONReq 如果err!=零{ 返回 } //进一步处理请求结构 if reqFunc!=零{ 请求函数 } var rsp *Rsp //业务逻辑函数调用 if serviceFunc!=零{ rsp,err = serviceFunc(c,req) } else if serviceOptFunc!=零{ rsp,err = serviceoptpfunc(c,req,opts...) }否则{ panic("必须设置ServiceFunc或ServiceFuncOpt ") } //处理响应 处理器sp(c,Rsp,err) } }

复制代码
这样,现在一个接口基本上只需要一行代码就可以实现(不包括具体的业务逻辑功能):

//简单请求,不需要身份验证 e.GET("/user/info/get ",ginrest。Do(nil,GetUserInfo)) //身份验证、绑定UID、处理 reqFunc := func(c *gin。上下文,req *UpdateUserInfoReq) { 请求。UID = GetUID(c) }//这里再多一步就是说明第一个参数是ReqFunc。 e.POST("/user/info/update ",Verify,ginrest。Do(reqFunc,UpdateUserInfo))


地址,并实现了一个基于gin的RESTful风格模板。
对象池/缓存
Golang标准库附带了一个线程安全的高性能对象池同步。池,可以根据物体的热度自动释放物体。但是,作为对象池,我们通常只放一种类型的对象进去,但是元素是同步的。池仍然是“接口{}”类型,所以我们可以简单地封装同步。池并使其元素具有特定的类型:
事实上,这里有一个简单的对象同步。Pool进行打包,然后添加一个ClearFunc()在回收对象时做一些清理操作。例如,我们需要使字节片的使用长度为零(容量保持不变)。

//创建一个新对象 键入NewFunc[T any] func() T

//清理对象 类型ClearFunc[T any] func(T) T

类型Pool[T any] struct { p同步。泳池 clearFunc }

func New[T any](New func New func[T],clear func clear func[T])* Pool[T]{ 如果newFunc == nil { panic("必须提供NewFunc ") } p := &Pool[T]{ clearFunc: clearFunc, } p.p.New = func() any { 返回newFunc() } 返回p }

//获取对象 func (p *Pool[T]) Get() T { 返回p.p.Get()。(吨) }

//返回对象 func (p *Pool[T]) Put(t T) { if p.clearFunc!=零{ t = p.clearFunc(t) } 投入产出 }

复制代码
用作字节数组对象池:

new func:= func()[]字节{ 返回make([]字节,大小,上限) } clear func:= func(b[]字节)[]字节{ return b[:0] } p := New(newFunc,clearFunc) Bytes := p.Get() //这里字节的类型是[]byte 页(page的缩写)上传(字节)

``` 复制代码 代码地址 缓存也是如此。目前,大多数缓存库都是基于' interface{} '或byte[]实现的,但我们仍然更喜欢直接操纵特定的类型,所以我们可以使用泛型来自己实现(或转换)一个缓存库。我还实现了一个通用的缓存策略库,其中包含LRU、LFU、ARC、NearlyLRU、TinyLFU等缓存策略。

# # # * 摘要 *

如你所见,实际上Golang泛型主要提供了代码抽象和封装的能力,使我们能够编写更多可重用的代码,避免到处复制代码,从而提高代码的可维护性和可读性,并从避免类型转换中获得一点点性能提升。 download:深入JavaScript高级语法-coderwhy大神

免责申明:本站发布的内容(图片、视频和文字)以转载和分享为主,文章观点不代表本站立场,如涉及侵权请联系站长邮箱:xbc-online@qq.com进行反馈,一经查实,将立刻删除涉嫌侵权内容。