drslez4322 2017-10-16 07:21
浏览 95
已采纳

如何正确地将带有String()方法的嵌入式结构序列化为JSON字符串?

 package main

 import (
    "fmt"
    "encoding/json"
 )

 type Ticket struct {
    From string
    To   string
}

func (t Ticket) String() string {
    return fmt.Sprintf("%s - %s", t.From, t.To)
}

type Passenger struct {
    Name string `json:"Name"`
    Tkt  Ticket `json:"Ticket"`
}

func main() {
    p := Passenger{}
    p.Name = "John"
    p.Tkt.From = "New York"
    p.Tkt.To = "Washington"

    buf, _ := json.Marshal(p)
    fmt.Println(string(buf))
}

This code outputs:

 {"Name":"John","Ticket":{"From":"New York","To":"Washington"}}

But, using json.Marshal() method (it's easy and friendly for complex struct), how to make it output like this:

 {"Name":"John","Ticket":"New York - Washington"}
  • 写回答

1条回答 默认 最新

  • douhe6181 2017-10-16 07:37
    关注

    To generate the JSON representation of a Go value, the encoding/json package checks if the value implements the json.Marshaler or the encoding.TextMarshaler interfaces, and if so, they are used / called (in this order). This is documented at json.Marshal():

    Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalJSON method to produce JSON. If no MarshalJSON method is present but the value implements encoding.TextMarshaler instead, Marshal calls its MarshalText method and encodes the result as a JSON string.

    The json/encoding package doesn't care about the String() method. So if you want to control the JSON representation / output of your value (the Ticket struct), implement json.Marshaler on it (in which you may call String() to your liking):

    func (t Ticket) MarshalJSON() ([]byte, error) {
        return []byte(`"` + t.String() + `"`), nil
    }
    

    Then the output will be as you desire:

    {"Name":"John","Ticket":"New York - Washington"}
    

    Try it on the Go Playground.

    One thing to look out for: if the string produced by Ticket.String() would contain a quotation mark ", the output would become invalid JSON, or more likely json.Marshal() would return an error.

    To take care of such escaping, best / easiest is to use the json package itself: tell it to JSON-encode the string result of Ticket.String():

    func (t Ticket) MarshalJSON() ([]byte, error) {
        return json.Marshal(t.String())
    }
    

    Now if we test it like this:

    p.Name = "John"
    p.Tkt.From = "New\" York" // CONTAINS QUOTE
    p.Tkt.To = "Washington"
    
    buf, err := json.Marshal(p)
    fmt.Println(string(buf), err)
    

    The output will still be a valid JSON (try it on the Go Playground):

    {"Name":"John","Ticket":"New\" York - Washington"} <nil>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 CATIA有些零件打开直接单机确定终止
  • ¥15 请问有会的吗,用MATLAB做
  • ¥15 phython如何实现以下功能?查找同一用户名的消费金额合并—
  • ¥15 ARIMA模型时间序列预测用pathon解决
  • ¥15 孟德尔随机化怎样画共定位分析图
  • ¥18 模拟电路问题解答有偿速度
  • ¥15 CST仿真别人的模型结果仿真结果S参数完全不对
  • ¥15 误删注册表文件致win10无法开启
  • ¥15 请问在阿里云服务器中怎么利用数据库制作网站
  • ¥60 ESP32怎么烧录自启动程序,怎么查看客户esp32板子上程序及烧录地址