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 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?