最近go1.18推出了泛型功能, 之前一直没有机会实战, 今天写代码的时候突然想到, 可以靠泛型来优化我的代码
由于我写的是自动化运维的网站, 需要调用很多别的服务的接口, 然后需要读取http的响应, 我们来看看现在我的写法
resp, err := global.IntranetClient.Do(req) if err != nil { global.Logger.Errorf("查询jumpserver storeNumber信息错误: %v", err) return err } //从这里开始全部都是重复代码 buffer := global.Pool.Get().(*bytes.Buffer) buffer.Reset() defer service.DeferBuffer(resp, buffer) _, err = io.Copy(buffer, resp.Body) if err != nil { global.Logger.Errorf("复制jumpserver storeNumber查询结果到buffer错误: %v", err) return err } response := []map[string]interface{}{} err = json.Unmarshal(buffer.Bytes(), &response) if err != nil { global.Logger.Errorf("复制jumpserver storeNumber查询结果为json错误: %v", err) return err }
从buffer := 这一行开始, 全部都是重复代码, 每一个http请求, 我要解析内容, 都需要重复这一段流程
- 从pool拿一个buffer
- 清空buffer
- 在defer函数中, close resp的body, 把buffer放回pool
- 使用io.Copy把http请求的响应体内容复制到buffer
- 把buffer解析为json
由于之前一直纠结于, 每个API的响应体的结构不同, 没有办法封装为一个函数来执行, 比如jumpserver的api响应是map[string]interface{}, foreman的响应是[]interface{},
今天突然想到可以通过泛型来解决这个工具类函数接收参数的问题,
工具函数的代码如下
type HttpResultData interface { *map[string]interface{} | *[]interface{} } func GetHttpResp[R HttpResultData](resp *http.Response, service string, result R) (err error) { buffer := global.Pool.Get().(*bytes.Buffer) buffer.Reset() defer DeferBuffer(resp, buffer) if _, err = io.Copy(buffer, resp.Body); err != nil { global.Logger.Errorf("复制%s的Http响应到buffer失败", err) return err } if err = json.Unmarshal(buffer.Bytes(), &result); err != nil { global.Logger.Errorf("解析%s的Http响应为json失败", err) return err } return }
我们定义了一个HttpResultData的泛型, 它包括了两种数据结构, 然后我们在GetHttpResp这个函数上定义接收这个泛型参数
在调用端的代码
result := []interface{}{} if err := service.GetHttpResp(resp, "jumpserver node", &result); err != nil { return err }
这样我们在调用的时候, 定义我们想要解析的json参数类型, 然后通过调用这个工具类的函数, 把http的响应体解析到我们传入的参数上, 非常的完美, 可以节省大量的冗余代码
发表回复