質問
Golang では、他のタイプのデータ (スライス、マップ、構造体など) を JSON 形式に変換する必要があることがよくあります。変換結果が予期したものと異なる場合があります。たとえば、空のスライスを JSON に変換すると、予期した「[]」ではなく「null」になります。サンプルコードは次のとおりです。
package main
import (
"encoding/json"
"fmt"
)
func main() {
var res []string
b, err := json.Marshal(res)
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
例を実行して結果を確認します。
$ go run main.go
null
結果の出力値は、予期された「[]」ではなく「null」になります。
理由
上記サンプルコードの res は、var キーワードにより string 型スライスとして宣言されていますが、このようなスライスは値が nil でメモリアドレスを指さない、ゼロ値スライスと呼ばれます。実際のタイトルでこの状況で登場するスライスがゼロ値スライスです 次に、ゼロ値スライスと空スライスについて紹介します。
Golang では、スライスはポインタ、長さ、容量の 3 つのプロパティを持つ可変長配列です。「ゼロ値スライス」と「空のスライス」は、2 つの特別な種類のスライスです。
- ゼロ値スライス: スライス タイプの変数が宣言されていても明示的に初期化されていない場合、その値はゼロ値スライスです。ゼロ値スライスにはメモリ空間が割り当てられず、その長さと容量はゼロです。ゼロ値スライスは nil スライスとも言えます。例えば:
var s []string
fmt.Println(s == nil) // 输出 "true"
- 空のスライス: 空のスライスの長さと容量もゼロですが、空ではあるがメモリが割り当てられた実際の配列を指します。空のスライスは、make 関数またはリテラル構文を使用して作成できます。例えば:
s := make([]string, 0)
fmt.Println(s == nil) // 输出 "false"
s := []string{}
fmt.Println(s == nil) // 输出 "false"
どちらの例でも、 s は長さ、容量がゼロの空のスライスですが、その値は nil ではありません。
ゼロ値スライスと空のスライスはほとんどの場合同じ意味で使用され、どちらも空のコレクションを表すために使用できます。ただし、スライスが明示的に初期化されているかどうかを区別する必要がある場合は、それらの違いに注意する必要があります。エンコーディング/json ライブラリは 2 つの異なる方法で処理し、ゼロ値のスライスを「null」としてエンコードし、空のスライスを「[]」としてエンコードします。これにより、インターフェイスが配列処理に "null" ではなく "[]" を予期している場合など、場合によっては問題が発生する可能性があります。
この時点で、この記事の質問に対する答えは皆さんすでにご存じだと思いますが、空のスライスを JSON 形式に変換した後に "[]" を取得したい場合は、make 関数またはリテラル構文を使用して、スライスを宣言する場合は、slice。簡単な例を見てみましょう。
package main
import (
"encoding/json"
"fmt"
)
func main() {
res := make([]string, 0)
// 或者 res:= []string{}
// 而非 var res []string
b, err := json.Marshal(res)
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
コードを実行して効果を確認します。
$ go run main.go
[]
期待通りの効果が得られていることがわかります。
まとめ
この記事では、ゼロ値スライス (nil スライス) と空のスライスの定義と違いについて説明します。空のスライスを JSON 形式に変換し、「null」の代わりに「[]」を取得したい場合、最良の方法は、スライスを作成するための make 関数またはリテラル数量構文。