天天看點

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