json tag 用法介紹

Go json 轉換時可以指定要把tag name換成指定的名稱,如:

type FooWithTag struct {
    Bar string `json:"tomato"`
}

則在經過 Marshal 後,就會變成:

{"tomato":"something"}

Reflect

reflect 可以讓我們在使用json時,輕易處理tag。

type Foo struct {
	Bar string `manners`
}

func Say(v interface{}) {
	t := reflect.TypeOf(v)
	for i := 0; i < t.NumField(); i++ {
		fmt.Printf("%v\n", t.Field(i).Tag)
	}
	// Output: manners
}

範例二

package main

import (
	"fmt"
	"reflect"
)

type Foo struct {
	Bar string `manners:"-"`
}

func main() {
	f := Foo{"I want a tomato"}
	Say(f)
	// Output:
	// I want a tomato pretty please
}

func Say(v interface{}) {
	rv := reflect.ValueOf(v)
	t := rv.Type()
	for i := 0; i < t.NumField(); i++ {
		if value, ok := t.Field(i).Tag.Lookup("manners"); ok {
			if value == "" || value == "-" {
				fmt.Printf("%s pretty please\n", rv.Field(i).String())
			}
		}
	}
}

範例三

package main

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

type Foo struct {
	Bar string `manners:"3"`
}

func main() {
	f := Foo{"I want a tomato"}
	Say(f)
	// Output:
	// I want a tomato pretty pretty pretty please
}

func Say(v interface{}) {
	rv := reflect.ValueOf(v)
	t := rv.Type()
	for i := 0; i < t.NumField(); i++ {
		if value, ok := t.Field(i).Tag.Lookup("manners"); ok {
			if rv.Field(i).Kind() == reflect.String {
				handleManners(rv.Field(i).String(), value)
			}
		}
	}
}

func handleManners(fieldValue, tagValue string) {
	var prettyTimes int
	if tagValue == "" || tagValue == "-" {
		prettyTimes = 1
	}
	if i, err := strconv.Atoi(tagValue); err == nil {
		prettyTimes = i
	}

	var sb strings.Builder
	sb.WriteString(fieldValue)
	for i := 0; i < prettyTimes; i++ {
		sb.WriteString(" pretty")
	}
	if prettyTimes > 0 {
		sb.WriteString(" please")
	}

	fmt.Println(sb.String())
}

參考文件