我有一个结构,我想根据上下文不同地制作成JSON。
例如,有时我想像这样编组:
type MyStruct struct {
Nickname string `json:"nickname"`
EmailAddress string `json:"email_address"`
PhoneNumber string `json:"-"`
MailingAddress string `json:"-"`
}
有时我想像这样编组:
type MyStruct struct {
Nickname string `json:"nickname"`
EmailAddress string `json:"email_address"`
PhoneNumber string `json:"phone_number"`
MailingAddress string `json:"mailing_address"`
}
有没有一种简单的方法可以做到这一点:
如果只有办法:
答案 0 :(得分:11)
我知道你明确提到"没有编写自定义封送程序"但是如果有人看到这个并且认为应该避免因为复杂性,定制编组来做你想做的事情真的很简单:
type MyStruct struct {
Nickname string `json:"nickname"`
EmailAddress string `json:"email_address"`
PhoneNumber string `json:"phone_number"`
MailingAddress string `json:"mailing_address"`
all bool
}
func (ms MyStruct) MarshalJSON() ([]byte, error) {
m := map[string]interface{}{} // ideally use make with the right capacity
m["nickname"] = ms.Nickname
m["email_address"] = ms.EmailAddress
if ms.all {
m["phone_number"] = ms.PhoneNumber
m["mailing_address"] = ms.MailingAddress
}
return json.Marshal(m)
}
如果all
字段应该由外部包设置,那么可以在结构上定义方法,或者可以将字段公开(不会影响JSON,因为它是通过编码的定制封送者。)
操场上的可运行示例:http://play.golang.org/p/1N_iBzvuW4
答案 1 :(得分:-1)
您可以使用反射,而不是最有效的解决方案,但它很方便。
func MarshalSubset(obj interface{}, fields ...string) ([]byte, error) {
if len(fields) == 0 {
return json.Marshal(obj)
}
out := make(map[string]interface{}, len(fields))
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
panic("not a struct")
}
typ := val.Type()
for _, f := range fields {
val := val.FieldByName(f).Interface()
rfld, _ := typ.FieldByName(f)
tag := strings.Split(rfld.Tag.Get("json"), ",")
if len(tag) > 0 {
f = tag[0]
}
out[f] = val
}
return json.Marshal(out)
}