Go的泛型初体验

最近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的响应体解析到我们传入的参数上, 非常的完美, 可以节省大量的冗余代码


评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注