2017-10-16 10 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()メソッドを使用して埋め込み構造体を正しくシリアル化するにはどうすればいいですか?

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

しかし、それをこのような出力作る方法を、(それは複雑な構造体のための簡単かつフレンドリーだ)json.Marshal()メソッドを使用して:JSONを生成するには

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

答えて

3

を値がjson.Marshalerまたはencoding.TextMarshalerのインターフェイスを実装しているかどうかを確認し、使用する場合は、この順序で使用/呼び出しされます。これは、json.Marshal()に記載されています。

マーシャルは値vを再帰的にトラバースします。遭遇した値がマーシャラインターフェイスを実装し、nilポインタでない場合、マーシャルはそのMarshalJSONメソッドを呼び出してJSONを生成します。 MarshalJSONメソッドが存在しないが、その値がencoding.TextMarshalerを代わりに実装する場合、MarshalはそのMarshalTextメソッドを呼び出し、その結果をJSON文字列としてエンコードします。

json/encodingパッケージはString()メソッドを気にしません。だから、あなたはあなたの値のJSON表現/出力(Ticket構造体)を制御したい場合は、(あなたがあなたの好みに合わせてString()を呼び出すことができている)、それにjson.Marshalerを実装:

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()) 
} 

Ticket.String()のJSONエンコード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

関連する問題