天天看点

golang 结构体标签 -- struct tag (八)

作者:kungze

结构体标签可以说是 golang 中一个比较有特殊的特性。在讲解 golang 结构体标签之前我们先来看一个结构体标签最常用的场景。有过 web 后端编程的经验的伙伴们应该都会有这样的感受,后端程序处理数据的流程可以抽象为:1、接受前端请求->处理请求->业务数据写入数据库;2、从数据库读取数据->处理业务->向前端返回数据。

在这两个过程中程序会有两次数据的转换:前端数据(json 数据或者 form 表单)与程序对象或结构体的互转,数据库数据(比如 sql 数据)与程序的对象或结构体的互转。

golang 结构体标签 -- struct tag (八)

在 golang 中我们借助 struct tag,这些转换都会特别简单。我们来看一个例子:

package main

import (
	"encoding/json"
	"net/http"
)

// json:"param-1" 和 json:"param-2 即为结构体标签,其
// 要紧跟在结构体属性后面使用反引号 `` 引起来。
type data struct {
	Param1 string `json:"param-1"`
	Param2 int    `json:"param-2"`
}

func main() {
	http.HandleFunc("/getjson", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		reps, err := json.Marshal(data{Param1: "I am a string", Param2: 2})
		if err != nil {
			panic(err)
		}
		w.Write([]byte(reps))
	})
	http.ListenAndServe("0.0.0.0:18080", nil)
}           

使用 go run main.go 启动程序后,在使用 curl 命令在检验结果:

# curl -i http://127.0.0.1:18080/getjson
HTTP/1.1 200 OK
Content-Type: application/json
Date: Fri, 30 Sep 2022 07:22:17 GMT
Content-Length: 39

{"param-1":"I am a string","param-2":2}           

从上面的例子我们看到借助结构体标签我们能很容易的完成 golang 结构体到 json 数据的转换。除了 json 还有很多其他 golang 库可以完成 golang 结构体到其他数据的转换,如:xml [1]、protocolbuf [2]; 还能用于数据库 orm 相关 beego orm [3]、gorm [4]。

reflect.StructTag

从上面内容我们了解到了使用 golang 结构体标签的方便之处,但是上面我们都是借助各种库来完成数据的转换的。如果这些库不好用,或者我们遇到一套特有的的数据规范第三方库处理不了,我们想自己写一套处理结构体标签的工具,这时候我们就需要掌握 reflect.StructTag,他是专门用于处理结构体标签的,上面提到的各种库底层都会用到 reflect.StructTag。

我们来看一个官方的例子:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type S struct {
		F string `species:"gopher" color:"blue"`
	}

	s := S{}
	st := reflect.TypeOf(s)
	field := st.Field(0)
	fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"))

}           

程序运行的输出结果:

blue gopher           

reflect.StructTag 非常简单,就包含了两个方法 Get 和 Lookup,详细的介绍可以参考官方文档,但是要想写出真正有用的工具还需要全面的掌握 golang reflect ,关于 golang reflect 在后续章节我也会逐步介绍到。

[1] https://pkg.go.dev/encoding/xml

[2] https://pkg.go.dev/google.golang.org/protobuf

[3] https://pkg.go.dev/github.com/astaxie/beego/orm

[4] https://github.com/go-gorm/gorm