2017-10-16 2 views
2
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)) 
} 

이 코드 출력 :JSON 문자열에 String() 메서드가 포함 된 struct를 올바르게 serialize하는 방법은 무엇입니까?

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

그러나, json.Marshal() 방법을 사용하여 (쉽게 복잡한 구조체에 대한 친절은), 어떻게 출력과 같이 만들 수 :

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

답변

3

는 JSON 생성 표현의 경우, encoding/json 패키지는 값이 json.Marshaler 또는 encoding.TextMarshaler 인터페이스를 구현하는지 확인하고, 그렇다면이 순서대로 사용/호출됩니다. 이것은 json.Marshal()에 문서화되어 있습니다.

마샬은 v 값을 재귀 적으로 통과합니다. 발생한 값이 마샬 러 인터페이스를 구현하고 nil 포인터가 아닌 경우 마샬 러는 MarshalJSON 메서드를 호출하여 JSON을 생성합니다. MarshalJSON 메서드가 없지만 값이 encoding.TextMarshaler를 대신 구현하면 Marshal은 해당 MarshalText 메서드를 호출하고 결과를 JSON 문자열로 인코딩합니다.

json/encoding 패키지는 String() 메소드에 신경 쓰지 않습니다. 당신이 당신의 값합니다 (Ticket 구조체)의 JSON 표현/출력을 제어하려는 경우 그래서,에 json.Marshaler을 (이 원하는대로 String()를 호출 할 수 있습니다) 구현 :

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

그런 다음 출력이 당신과 같이 될 것입니다 욕망 :

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

Go Playground에서 시도해보십시오.

한 가지 피려 : Ticket.String()에 의해 생성 된 string는 인용 부호 "를 포함 할 경우, 출력은 무효 JSON 될 것, 또는 가능성 json.Marshal()는 오류를 반환합니다. 우리는이 같은 테스트 경우 지금

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

: JSON 인코딩에 Ticket.String()string 결과를 알려 :

는 이스케이프를 돌봐하기 위해 최선/가장 쉬운 자체가 json 패키지를 사용하는 것입니다 :

:

p.Name = "John" 
p.Tkt.From = "New\" York" // CONTAINS QUOTE 
p.Tkt.To = "Washington" 

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

출력은 여전히 ​​유효한 JSON합니다 (Go Playground에 그것을 시도를)입니다

{"Name":"John","Ticket":"New\" York - Washington"} <nil> 
+0

멋진 솔루션. 고맙습니다. –

+0

덧붙여 말하자면'% s' 대신에'% q'을 사용하면 문자열을 인용 할 것입니다. https://play.golang.org/p/RYhaMM5kpd – Kaedys

+1

@Kaedys 당신은 입력에서 잠재적 인용문을 잊었다는 것을 깨닫게했습니다. 나는'json' 패키지 자체의 사용을 제안하도록 질문을 업데이트했다. – icza

관련 문제