Help us understand the problem. What is going on with this article?

空のSliceの宣言方法の違い

More than 1 year has passed since last update.

はじめに

Golangの空スライスの宣言でハマったので調べてみた。

宣言方法

Golangで空のスライスを作ろうとすると

var s1 []string
s2 := []string{}
s3 := make([]string, 0)

を使うはず。

違い

var s1 []string         // nilスライス
s2 := []string{}        // 空スライス
s3 := make([]string, 0) // 空スライス

下2つは同じみたい。varで宣言するとnilのスライスができる。
一応調べたコード。

package main

import (
    "fmt"
)

func main() {
    var s1 []string         // nilスライス
    s2 := []string{}        // 空スライス
    s3 := make([]string, 0) // 空スライス

    fmt.Println(s1)                   // []
    fmt.Printf("%#v\n", s1)           // []string(nil)
    fmt.Println(s1, len(s1), cap(s1)) // [] 0 0

    fmt.Println(s2)                   // []
    fmt.Printf("%#v\n", s2)           // []string{}
    fmt.Println(s2, len(s2), cap(s2)) // [] 0 0

    fmt.Println(s3)                   // []
    fmt.Printf("%#v\n", s3)           // []string{}
    fmt.Println(s3, len(s3), cap(s3)) // [] 0 0
}

気をつけること

json.Marshalでの挙動の違い

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    var s1 []string
    s2 := []string{}
    s3 := make([]string, 0)

    j1, _ := json.Marshal(s1)
    fmt.Println(string(j1)) // null

    j2, _ := json.Marshal(s2)
    fmt.Println(string(j2)) // []

    j3, _ := json.Marshal(s3)
    fmt.Println(string(j3)) // []
}

個人的にハマった理由

僕はJetBrainsのIDE大好きなので、Go書くのも特に考えずIntelliJ IDEAかGolandを使っていた。
さきほどの2つめの宣言

s2 := []string{}

これを書いていると
スクリーンショット 2018-12-02 0.40.00.png
Empty slice declaration via literal
Inspection info: Reports slice declaration with empty literal initializer instead of nil.

波線が出るので
スクリーンショット 2018-12-02 1.02.03.png
言われるがままReplaceすると
スクリーンショット 2018-12-02 1.02.09.png

var s2 []string

varに変えられた。
こちらの書き方のほうがいいのかなくらいの認識で使っていたが、上記JSON化の際に挙動が変わって困った。

package main

import (
    "fmt"
)

func main() {
    var s1 []string
    s2 := []string{}
    s3 := make([]string, 0)

    fmt.Println(s1) // []

    fmt.Println(s2) // []

    fmt.Println(s3) // []
}

fmt.Printlnでは同じ表示になったのでしばらく困った。

結論

基本的にはvarを使用して、nilスライスではだめな箇所は明示的にmake()を使用する感じにした。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away