结构字段标签


对于 JSON 或 XML 等具有结构性的数据,在 Go 中经常会使用struct定义数据结构,例如,底下这个程序可以将简单的结构转为 JSON:

package main

import (
    "fmt"
    "reflect"
    "strings"
)

type Customer struct {
    Name string
    City string
}

func ToJSON(obj interface{}) string {
    t := reflect.TypeOf(obj)
    v := reflect.ValueOf(obj)

    var b []string  
    for i, n := 0, t.NumField(); i < n; i++ {
        f := t.Field(i)
        b = append(b, fmt.Sprintf(`"%s": "%s"`, f.Name, v.FieldByName(f.Name)))
    }

    return fmt.Sprintf("{%s}", strings.Join(b, ","))
}

func main() {
    cust := Customer{"Justin", "Kaohsiung"}
    // 显示 {"Name": "Justin","City": "Kaohsiung"}
    fmt.Println(ToJSON(cust))
}

然而,Go 的惯例中,公开的结构字段名称通常是大写的,如果你的 JSON 要求的是小写的字段名称,或者是其他名称,可以使用字段标签(Field tag)。例如:

package main

import (
    "fmt"
    "reflect"
    "strings"
)

type Customer struct {
    Name string `name`
    City string `city`
}

func ToJSON(obj interface{}) string {
    t := reflect.TypeOf(obj)
    v := reflect.ValueOf(obj)
    var b []string

    for i, n := 0, t.NumField(); i < n; i++ {
        f := t.Field(i)
        b = append(b, fmt.Sprintf(`"%s": "%s"`, f.Tag, v.FieldByName(f.Name)))
    }

    return fmt.Sprintf("{%s}", strings.Join(b, ","))
}

func main() {
    cust := Customer{"Justin", "Kaohsiung"}
    // 显示 {"name": "Justin","city": "Kaohsiung"}
    fmt.Println(ToJSON(cust))
}

字段标签可以在反射时,使用FieldTag来获取,虽然字段标签可以是任意格式字符串,然而惯例上,会由key: "value"的格式组成,符合此格式的话,可以使用TagLookup来查找value,它返回两个值,第一个值是value,第二个值指出是否有对应的名称,例如:

package main

import (
    "fmt"
    "reflect"
    "strings"
)

type Customer struct {
    Name string `json:"name"`
    City string `json:"city"`
}

func ToJSON(obj interface{}) string {
    t := reflect.TypeOf(obj)
    v := reflect.ValueOf(obj)
    var b []string

    for i, n := 0, t.NumField(); i < n; i++ {
        f := t.Field(i)
        fv, _ := f.Tag.Lookup("json")
        b = append(b, fmt.Sprintf(`"%s": "%s"`, fv, v.FieldByName(f.Name)))
    }

    return fmt.Sprintf("{%s}", strings.Join(b, ","))
}

func main() {
    cust := Customer{"Justin", "Kaohsiung"}
    // 显示 {"name": "Justin","city": "Kaohsiung"}
    fmt.Println(ToJSON(cust))
}

实际上,如果要将结构转为 JSON 格式字符串,可以使用encoding/json,例如:

package main

import (
    "encoding/json"
    "fmt"
)

type Customer struct {
    Name string `json:"name"`
    City string `json:"city"`
}

func main() {
    cust := Customer{"Justin", "Kaohsiung"}
    b, _ := json.Marshal(cust)
    // 显示 {"name": "Justin","city": "Kaohsiung"}
    fmt.Println(string(b))
}




展开阅读全文