GolangによるJSONシーケンス化
13726 ワード
総覧
JSONは最もポピュラーなシーケンス化フォーマットの一つです.これは人間が読むことができて、かなり簡潔で、どんなWebアプリケーションでもJavaScriptを使って簡単に解析することができます.Goは現代のプログラミング言語として、JSONシーケンス化を標準ライブラリで一流のサポートを提供しています.
しかし、ここには隅と隙間があります.このチュートリアルでは、JSONを効率的にシーケンス化する方法と、任意のデータと構造化されたデータをJSONからシーケンス化および逆シーケンス化する方法について説明します.シーケンス列挙などの高度なシーンの処理方法も学習します.
jsonパッケージ
Goは、その標準ライブラリの符号化パケットにおいて、複数のシーケンス化フォーマットをサポートする.その一つが流行しているJSON形式です.Marshal()関数を使用して、Golang値を1バイトスライスにシーケンス化できます.Unmarshal()関数を使用して、バイトのセグメントをGolang値に逆シーケンス化できます.これは簡単です.本明細書のコンテキストでは、次の用語は同等です.シーケンス化/符号化/グループ 逆シーケンス化/復号化/デグループ 潜在的な階層化データ構造とバイトストリームを相互変換しているという事実を反映しているため、シーケンス化が好きです.
元帥
Marshal()関数は、Goで空のインタフェースを表し、バイトとエラーを返す任意の内容を受け入れることができます.これは署名です.
Marshal()が入力値をシーケンス化できない場合、nil以外のエラーが返されます.Marshal()にはいくつかの厳しい制限があります(カスタムグループを使用して克服する方法は後述します):マッピングキーは文字列でなければなりません. マッピング値は、jsonパケットがシーケンス可能なタイプである必要があります. では、チャネル、複雑さ、および機能はサポートされていません. では、循環データ構造はサポートされていません. ポインタは、ポインタが指す値(ポインタがnilの場合はnull)として符号化(復号)される. 元帥
Unmarshal()関数は、通常、構造または基本タイプのポインタを指す有効なJSONとターゲットインタフェースを表すことが期待されるバイトスライスを使用します.JSONをインタフェースに逆シーケンス化します.シーケンス化に失敗すると、エラーが返されます.署名です.
単純タイプのシーケンス化
jsonパッケージを使用するなど、簡単なタイプを簡単にシーケンス化できます.結果は完全なJSONオブジェクトではなく、単純な文字列になります.ここで、int 5は、文字列「5」に対応するバイト配列にシーケンス化される[53].
サポートされていないタイプ(関数など)をシーケンス化しようとすると、エラーメッセージが表示されます.
地図を使用して任意のデータをシーケンス化
JSONの強みは,任意の階層データをうまく表現できることである.JSONパケットはこれをサポートしており、JSON階層を表すために共通のNullインタフェースを使用しています.これは逆シーケンス化され、その後にツリーがシーケンス化される例で、各ノードにはint値と左右の2つのブランチがあり、別のノードまたはnullが含まれる場合があります.
JSON空の値はGo nilに等しい.出力から、
インタフェースの汎用マッピングを巡回するには、タイプブレークスルーを使用する必要があります.例:
構造化データのシーケンス化
構造化データの使用は、通常より良い選択です.囲碁はJSONシーケンス化から/素晴らしいサポート
任意のJSON方法に比べて、これは素晴らしいし、きれいです.しかし、これは有効ですか?違います.エラーはありませんが、JSONは私たちのツリーオブジェクトを埋めていません.
問題は、ツリーフィールドがプライベートであることです.JSONシーケンス化は共通フィールドにのみ適用されます.したがって、
jsonパケットは、JSONのマッピングされていないフィールドおよび
これは新しいJSONで、ツリーのルートノードは「root」とマークされ、Tagフィールドに正しくシーケンス化され、出力に印刷されています.
カスタムグループの作成
Marshal()関数の要件を満たしていないオブジェクトをシーケンス化する必要があることがよくあります.たとえば、intキーを使用してマッピングをシーケンス化したい場合があります.この場合、
スペルに関する注意事項:Goでは、メソッド名の後に「er」接尾辞を付けることで、インタフェースを単一のメソッドで命名することを約束します.したがって、より一般的なスペルが「Marshaller」(ダブルL)であっても、インタフェース名は「Marshaler」(シングルL)にすぎない.
以下に、MarshalerインタフェースとUnmarshalerインタフェースを示します.
組み込みタイプまたは組み込みタイプの組合せ(たとえば
UnmarshalJSON()メソッドの役割は正反対です.データバイト配列を
これはプログラムで使用する方法です.
シーケンス列挙
Go列挙のシーケンス化は面倒かもしれません.Go jsonのシーケンス化に関する文章を書く考えは、同僚が列挙をどのようにシーケンス化するかについて私に聞いたことから来ています.これはGo
intと考えられ、多くの点で可能ですが、直接シーケンス化することはできません.カスタム封送解体/解体解体解体を作成する必要があります.前節の後、これは問題ではありません.次の
この
予想される出力は「Uno:1」ですが、「Uno:0」です.何があったの?グループ/グループ解除コードにエラーはありません.列挙をシーケンス化する場合は、列挙を値で埋め込むことはできません.列挙を指すポインタを埋め込む必要があります.これは、予定通りに作業できる修正バージョンです.
結論
Goは、JSONをシーケンス化および逆シーケンス化するための多くのオプションを提供する.符号化/jsonパケットのいきさつを理解し,その機能を利用することが重要である.
このチュートリアルでは、分かりにくいGo列挙をシーケンス化する方法など、すべての機能を把握します.
いくつかのオブジェクトをシーケンス化します!
翻訳:https://code.tutsplus.com/tutorials/json-serialization-with-golang--cms-30209
JSONは最もポピュラーなシーケンス化フォーマットの一つです.これは人間が読むことができて、かなり簡潔で、どんなWebアプリケーションでもJavaScriptを使って簡単に解析することができます.Goは現代のプログラミング言語として、JSONシーケンス化を標準ライブラリで一流のサポートを提供しています.
しかし、ここには隅と隙間があります.このチュートリアルでは、JSONを効率的にシーケンス化する方法と、任意のデータと構造化されたデータをJSONからシーケンス化および逆シーケンス化する方法について説明します.シーケンス列挙などの高度なシーンの処理方法も学習します.
jsonパッケージ
Goは、その標準ライブラリの符号化パケットにおいて、複数のシーケンス化フォーマットをサポートする.その一つが流行しているJSON形式です.Marshal()関数を使用して、Golang値を1バイトスライスにシーケンス化できます.Unmarshal()関数を使用して、バイトのセグメントをGolang値に逆シーケンス化できます.これは簡単です.本明細書のコンテキストでは、次の用語は同等です.
元帥
Marshal()関数は、Goで空のインタフェースを表し、バイトとエラーを返す任意の内容を受け入れることができます.これは署名です.
func Marshal(v interface{}) ([]byte, error)
Marshal()が入力値をシーケンス化できない場合、nil以外のエラーが返されます.Marshal()にはいくつかの厳しい制限があります(カスタムグループを使用して克服する方法は後述します):
Unmarshal()関数は、通常、構造または基本タイプのポインタを指す有効なJSONとターゲットインタフェースを表すことが期待されるバイトスライスを使用します.JSONをインタフェースに逆シーケンス化します.シーケンス化に失敗すると、エラーが返されます.署名です.
func Unmarshal(data []byte, v interface{}) error
単純タイプのシーケンス化
jsonパッケージを使用するなど、簡単なタイプを簡単にシーケンス化できます.結果は完全なJSONオブジェクトではなく、単純な文字列になります.ここで、int 5は、文字列「5」に対応するバイト配列にシーケンス化される[53].
// Serialize int
var x = 5
bytes, err := json.Marshal(x)
if err != nil {
fmt.Println("Can't serislize", x)
}
fmt.Printf("%v => %v, '%v'
", x, bytes, string(bytes))
// Deserialize int
var r int
err = json.Unmarshal(bytes, &r)
if err != nil {
fmt.Println("Can't deserislize", bytes)
}
fmt.Printf("%v => %v
", bytes, r)
Output:
- 5 => [53], '5'
- [53] => 5
サポートされていないタイプ(関数など)をシーケンス化しようとすると、エラーメッセージが表示されます.
// Trying to serialize a function
foo := func() {
fmt.Println("foo() here")
}
bytes, err = json.Marshal(foo)
if err != nil {
fmt.Println(err)
}
Output:
json: unsupported type: func()
地図を使用して任意のデータをシーケンス化
JSONの強みは,任意の階層データをうまく表現できることである.JSONパケットはこれをサポートしており、JSON階層を表すために共通のNullインタフェースを使用しています.これは逆シーケンス化され、その後にツリーがシーケンス化される例で、各ノードにはint値と左右の2つのブランチがあり、別のノードまたはnullが含まれる場合があります.
JSON空の値はGo nilに等しい.出力から、
json.Unmarshal()
関数は、ネストされたインタフェースマッピングからなり、値タイプをintに保持するJSON blobをGoデータ構造に変換することに成功した.json.Marshal()
関数は、得られたネストされたオブジェクトを同じJSON表現にシーケンス化することに成功した.// Arbitrary nested JSON
dd := `
{
"value": 3,
"left": {
"value": 1,
"left": null,
"right": {
"value": 2,
"left": null,
"right": null
}
},
"right": {
"value": 4,
"left": null,
"right": null
}
}`
var obj interface{}
err = json.Unmarshal([]byte(dd), &obj)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("--------
", obj)
}
data, err = json.Marshal(obj)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("--------
", string(data))
}
}
Output:
--------
map[right:map[value:4
left:
right:]
value:3
left:map[left:
right:map[value:2
left:
right:]
value:1]]
--------
{"left":{
"left":null,
"right":{"left":null,"right":null,"value":2},
"value":1},
"right":{"left":null,
"right":null,
"value":4},
"value":3}
インタフェースの汎用マッピングを巡回するには、タイプブレークスルーを使用する必要があります.例:
func dump(obj interface{}) error {
if obj == nil {
fmt.Println("nil")
return nil
}
switch obj.(type) {
case bool:
fmt.Println(obj.(bool))
case int:
fmt.Println(obj.(int))
case float64:
fmt.Println(obj.(float64))
case string:
fmt.Println(obj.(string))
case map[string]interface{}:
for k, v := range(obj.(map[string]interface{})) {
fmt.Printf("%s: ", k)
err := dump(v)
if err != nil {
return err
}
}
default:
return errors.New(
fmt.Sprintf("Unsupported type: %v", obj))
}
return nil
}
構造化データのシーケンス化
構造化データの使用は、通常より良い選択です.囲碁はJSONシーケンス化から/素晴らしいサポート
structs
までのstruct
のラベルを提供しています.JSONツリーに対応するstruct
と、よりスマートなDump()
関数を作成して印刷します.type Tree struct {
value int
left *Tree
right *Tree
}
func (t *Tree) Dump(indent string) {
fmt.Println(indent + "value:", t.value)
fmt.Print(indent + "left: ")
if t.left == nil {
fmt.Println(nil)
} else {
fmt.Println()
t.left.Dump(indent + " ")
}
fmt.Print(indent + "right: ")
if t.right == nil {
fmt.Println(nil)
} else {
fmt.Println()
t.right.Dump(indent + " ")
}
}
任意のJSON方法に比べて、これは素晴らしいし、きれいです.しかし、これは有効ですか?違います.エラーはありませんが、JSONは私たちのツリーオブジェクトを埋めていません.
jsonTree := `
{
"value": 3,
"left": {
"value": 1,
"left": null,
"right": {
"value": 2,
"left": null,
"right": null
}
},
"right": {
"value": 4,
"left": null,
"right": null
}
}`
var tree Tree
err = json.Unmarshal([]byte(dd), &tree)
if err != nil {
fmt.Printf("- Can't deserislize tree, error: %v
", err)
} else {
tree.Dump("")
}
Output:
value: 0
left:
right:
問題は、ツリーフィールドがプライベートであることです.JSONシーケンス化は共通フィールドにのみ適用されます.したがって、
struct
フィールドを開示することができる.jsonパッケージは、小文字キー「value」、「left」、「right」を対応する大文字フィールド名に透明に変換できるほどスマートです.type Tree struct {
Value int `json:"value"`
Left *Tree `json:"left"`
Right *Tree `json:"right"`
}
Output:
value: 3
left:
value: 1
left:
right:
value: 2
left:
right:
right:
value: 4
left:
right:
jsonパケットは、JSONのマッピングされていないフィールドおよび
struct
プライベートフィールドを黙々と無視します.ただし、JSONの特定のキーをstruct
の異なる名前のフィールドにマッピングする場合があります.このためにstruct
タグを使用できます.たとえば、JSONに「ラベル」という別のフィールドを追加したとしますが、構造内で「Tag」というフィールドにマッピングする必要があります.type Tree struct {
Value int
Tag string `json:"label"`
Left *Tree
Right *Tree
}
func (t *Tree) Dump(indent string) {
fmt.Println(indent + "value:", t.Value)
if t.Tag != "" {
fmt.Println(indent + "tag:", t.Tag)
}
fmt.Print(indent + "left: ")
if t.Left == nil {
fmt.Println(nil)
} else {
fmt.Println()
t.Left.Dump(indent + " ")
}
fmt.Print(indent + "right: ")
if t.Right == nil {
fmt.Println(nil)
} else {
fmt.Println()
t.Right.Dump(indent + " ")
}
}
これは新しいJSONで、ツリーのルートノードは「root」とマークされ、Tagフィールドに正しくシーケンス化され、出力に印刷されています.
dd := `
{
"label": "root",
"value": 3,
"left": {
"value": 1,
"left": null,
"right": {
"value": 2,
"left": null,
"right": null
}
},
"right": {
"value": 4,
"left": null,
"right": null
}
}`
var tree Tree
err = json.Unmarshal([]byte(dd), &tree)
if err != nil {
fmt.Printf("- Can't deserislize tree, error: %v
", err)
} else {
tree.Dump("")
}
Output:
value: 3
tag: root
left:
value: 1
left:
right:
value: 2
left:
right:
right:
value: 4
left:
right:
カスタムグループの作成
Marshal()関数の要件を満たしていないオブジェクトをシーケンス化する必要があることがよくあります.たとえば、intキーを使用してマッピングをシーケンス化したい場合があります.この場合、
Marshaler
およびUnmarshaler
インタフェースを実装することで、カスタム・グループ化/解Unmarshaler
を記述できます.スペルに関する注意事項:Goでは、メソッド名の後に「er」接尾辞を付けることで、インタフェースを単一のメソッドで命名することを約束します.したがって、より一般的なスペルが「Marshaller」(ダブルL)であっても、インタフェース名は「Marshaler」(シングルL)にすぎない.
以下に、MarshalerインタフェースとUnmarshalerインタフェースを示します.
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
組み込みタイプまたは組み込みタイプの組合せ(たとえば
map[int]string
)をシーケンス化する場合でも、カスタムシーケンス化時にタイプを作成する必要があります.ここでは、タイプIntStringMap
という名前のインタフェースを定義し、Marshaler
およびUnmarshaler
を実装します.MarshalJSON()
メソッドは、自身のint鍵を文字列に変換し、標準のmap[string]string
関数を使用して文字列鍵を使用して地図をシーケンス化するjson.Marshal()
を作成する.type IntStringMap map[int]string
func (m *IntStringMap) MarshalJSON() ([]byte, error) {
ss := map[string]string{}
for k, v := range *m {
i := strconv.Itoa(k)
ss[i] = v
}
return json.Marshal(ss)
}
UnmarshalJSON()メソッドの役割は正反対です.データバイト配列を
map[string]string
に逆シーケンス化し、各文字列キーをintに変換して埋め込みます.func (m *IntStringMap) UnmarshalJSON(data []byte ) error {
ss := map[string]string{}
err := json.Unmarshal(data, &ss)
if err != nil {
return err
}
for k, v := range ss {
i, err := strconv.Atoi(k)
if err != nil {
return err
}
(*m)[i] = v
}
return nil
}
これはプログラムで使用する方法です.
m := IntStringMap{4: "four", 5: "five"}
data, err := m.MarshalJSON()
if err != nil {
fmt.Println(err)
}
fmt.Println("IntStringMap to JSON: ", string(data))
m = IntStringMap{}
jsonString := []byte("{\"1\": \"one\", \"2\": \"two\"}")
m.UnmarshalJSON(jsonString)
fmt.Printf("IntStringMap from JSON: %v
", m)
fmt.Println("m[1]:", m[1], "m[2]:", m[2])
Output:
IntStringMap to JSON: {"4":"four","5":"five"}
IntStringMap from JSON: map[2:two 1:one]
m[1]: one m[2]: two
シーケンス列挙
Go列挙のシーケンス化は面倒かもしれません.Go jsonのシーケンス化に関する文章を書く考えは、同僚が列挙をどのようにシーケンス化するかについて私に聞いたことから来ています.これはGo
enum
です.定数ゼロと1は整数0と1に等しい.type EnumType int
const (
Zero EnumType = iota
One
)
intと考えられ、多くの点で可能ですが、直接シーケンス化することはできません.カスタム封送解体/解体解体解体を作成する必要があります.前節の後、これは問題ではありません.次の
MarshalJSON()
およびUnmarshalJSON()
は、定数ZEROおよびONEを対応する文字列「Zero」および「One」/に逆シーケンス化する.func (e *EnumType) UnmarshalJSON(data []byte) error {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return err
}
value, ok := map[string]EnumType{"Zero": Zero, "One": One}[s]
if !ok {
return errors.New("Invalid EnumType value")
}
*e = value
return nil
}
func (e *EnumType) MarshalJSON() ([]byte, error) {
value, ok := map[EnumType]string{Zero: "Zero", One:"One"}[*e]
if !ok {
return nil, errors.New("Invalid EnumType value")
}
return json.Marshal(value)
}
この
EnumType
をstruct
に埋め込み、シーケンス化してみましょう.main関数はEnumContainer
を作成し、int 1に等しい名前「Uno」およびenum
定数ONE
の値に初期化します.type EnumContainer struct {
Name string
Value EnumType
}
func main() {
x := One
ec := EnumContainer{
"Uno",
x,
}
s, err := json.Marshal(ec)
if err != nil {
fmt.Printf("fail!")
}
var ec2 EnumContainer
err = json.Unmarshal(s, &ec2)
fmt.Println(ec2.Name, ":", ec2.Value)
}
Output:
Uno : 0
予想される出力は「Uno:1」ですが、「Uno:0」です.何があったの?グループ/グループ解除コードにエラーはありません.列挙をシーケンス化する場合は、列挙を値で埋め込むことはできません.列挙を指すポインタを埋め込む必要があります.これは、予定通りに作業できる修正バージョンです.
type EnumContainer struct {
Name string
Value *EnumType
}
func main() {
x := One
ec := EnumContainer{
"Uno",
&x,
}
s, err := json.Marshal(ec)
if err != nil {
fmt.Printf("fail!")
}
var ec2 EnumContainer
err = json.Unmarshal(s, &ec2)
fmt.Println(ec2.Name, ":", *ec2.Value)
}
Output:
Uno : 1
結論
Goは、JSONをシーケンス化および逆シーケンス化するための多くのオプションを提供する.符号化/jsonパケットのいきさつを理解し,その機能を利用することが重要である.
このチュートリアルでは、分かりにくいGo列挙をシーケンス化する方法など、すべての機能を把握します.
いくつかのオブジェクトをシーケンス化します!
翻訳:https://code.tutsplus.com/tutorials/json-serialization-with-golang--cms-30209