国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Golang > 正文

golang如何使用struct的tag屬性的詳細介紹

2020-04-01 18:50:52
字體:
來源:轉載
供稿:網友

從一個例子說起

我們經常會碰到下面格式的struct定義:

type Person struct {  Name string `json:"name"`  Age int  `json:"age"`}

這個struct定義一個叫做Person的類型,包含兩個域Name和Age;但是在域的后面有神奇的 json:"name" ,這個用來干什么用?這篇文章試圖來解釋這個問題。

當golang的對象需要和json做轉換的時候,我們就經常用到這個特性。

有兩點注意的地方:

1、如果一個域不是以大寫字母開頭的,那么轉換成json的時候,這個域是被忽略的。

$ cat main.gopackage mainimport (  "fmt"  "encoding/json")type Person struct {  Name string `json:"name"`  age int  `json:"age"`}func main() {  person := Person { "tom", 12 }  if b, err := json.Marshal(person); err != nil {    fmt.Printf("error: %s", err.Error())  } else {    fmt.Printf("value: %s", b)  }}$ go build -o main main.go $ ./mainvalue: {"name":"tom"}

我們看到轉換成json串之后,name正常輸出了,而age被丟棄了,因為age以小寫字母開頭。

2、如果沒有使用 json:"name" tag,那么輸出的json字段名和域名是一樣的。

$ cat main.gopackage mainimport (  "fmt"  "encoding/json")type Person struct {  Name string  Age int}func main() {  person := Person { "tom", 12 }  if b, err := json.Marshal(person); err != nil {    fmt.Printf("error: %s", err.Error())  } else {    fmt.Printf("value: %s", b)  }}$ go build -o main main.go $ ./mainvalue: {"Name":"tom","Age":12}

我們看到輸出的json串使用的是struct定義的字段名。

總結一下, json:"name" 格式串是用來指導json.Marshal/Unmarshal,在進行json串和golang對象之間轉換的時候映射字段名使用的。再舉一個例子,json串和golang域名字可以任意轉換:

$ cat main.gopackage mainimport (  "fmt"  "encoding/json")type Person struct {  Name string  `json:"age"`  Age int    `json:"address"`}func main() {  person := Person { "tom", 12 }  if b, err := json.Marshal(person); err != nil {    fmt.Printf("error: %s", err.Error())  } else {    fmt.Printf("value: %s", b)  }}$ go build -o main main.go $ ./mainvalue: {"age":"tom","address":12}

這個例子我們把Name映射成了 age,而把Age映射成address,當然這是個奇葩的映射,沒有任何正向意義,只有負向意義,只是為了說明可以進行任何名字映射而已。

如果我們去看json包的源代碼,我可以看到在encoding/json/encode.go, encoding/json/decode.go里面有讀取tag值得相關代碼。

tag := sf.Tag.Get("json")

也就是說這個json的tag是被json.Marshal和json.Unmarshal來使用的。

我們如何使用tag

還是以前的例子,Person有一個域Age,我們能不能限定Age的值在1-100之間,不至于太大,否則這個值沒有意義了。

$ cat main.gopackage mainimport (  "fmt"  "strings"  "strconv"  "reflect" _ "encoding/json")type Person struct {  Name string  `json:"name"`  Age int    `json:"age" valid:"1-100"`}func (p * Person) validation() bool {  v := reflect.ValueOf(*p)  tag := v.Type().Field(1).Tag.Get("valid")  val := v.Field(1).Interface().(int)  fmt.Printf("tag=%v, val=%v/n", tag, val)    result := strings.Split(tag, "-")  var min, max int  min, _ = strconv.Atoi(result[0])  max, _ = strconv.Atoi(result[1])  if val >= min && val <= max {    return true  } else {    return false  }}func main() {  person1 := Person { "tom", 12 }  if person1.validation() {    fmt.Printf("person 1: valid/n")  } else {    fmt.Printf("person 1: invalid/n")  }  person2 := Person { "tom", 250 }  if person2.validation() {    fmt.Printf("person 2 valid/n")  } else {    fmt.Printf("person 2 invalid/n")  }}

這么例子我們給Person添加了一個validate函數,validate驗證age是不是合理。

這個函數可以擴展對任意struct的任意valid域進行驗證。

$ cat main.gopackage mainimport (  "fmt"  "strings"  "strconv"  "reflect" _ "encoding/json")type Person struct {  Name string  `json:"name"`  Age int    `json:"age" valid:"1-100"`}type OtherStruct struct {  Age int    `valid:"20-300"`}func validateStruct(s interface{}) bool { v := reflect.ValueOf(s) for i := 0; i < v.NumField(); i++ {  fieldTag  := v.Type().Field(i).Tag.Get("valid")  fieldName  := v.Type().Field(i).Name  fieldType  := v.Field(i).Type()  fieldValue := v.Field(i).Interface()  if fieldTag == "" || fieldTag == "-" {    continue  }  if fieldName == "Age" && fieldType.String() == "int" {    val := fieldValue.(int)    tmp := strings.Split(fieldTag, "-")    var min, max int    min, _ = strconv.Atoi(tmp[0])    max, _ = strconv.Atoi(tmp[1])    if val >= min && val <= max {      return true    } else {      return false    }  } } return true}func main() {  person1 := Person { "tom", 12 }  if validateStruct(person1) {    fmt.Printf("person 1: valid/n")  } else {    fmt.Printf("person 1: invalid/n")  }  person2 := Person { "jerry", 250 }  if validateStruct(person2) {    fmt.Printf("person 2: valid/n")  } else {    fmt.Printf("person 2: invalid/n")  }  other1 := OtherStruct { 12 }  if validateStruct(other1) {    fmt.Printf("other 1: valid/n")  } else {    fmt.Printf("other 1: invalid/n")  }  other2 := OtherStruct { 250 }  if validateStruct(other2) {    fmt.Printf("other 2: valid/n")  } else {    fmt.Printf("other 2: invalid/n")  }}

在這個例子中我們定義了一個函數validateStruct,接受任意一個struct作為參數;validateStruct為驗證struct中所有定義的Age字段,如果字段名字是Age,字段類型是int,并且定義了valid tag,那么就會驗證這個valid是否有效。

看執行結果:

$ go build -o main main.go 
$ ./main
person 1: valid
person 2: invalid
other 1: invalid
other 2: valid

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 睢宁县| 仙居县| 长顺县| 浪卡子县| 务川| 乌兰察布市| 北辰区| 镇坪县| 颍上县| 疏勒县| 乌兰浩特市| 寿宁县| 库尔勒市| 南通市| 教育| 长治县| 宝应县| 吕梁市| 和硕县| 雷州市| 五常市| 吉隆县| 新昌县| 出国| 额济纳旗| 珠海市| 康马县| 都江堰市| 威宁| 滦南县| 海城市| 深圳市| 独山县| 微山县| 克山县| 铜梁县| 丰原市| 辽源市| 西盟| 田阳县| 年辖:市辖区|