27635


[こちらのブログ](http://jxck.hatenablog.com/entry/golang-slice-
internals2)にスライスは、関数内で変更すると呼び出し元も変わると書かれていますが、以下のコードでは変わりませんでした。  
なぜでしょうか。

<https://play.golang.org/p/W25AjW4Utx>

返り値で返すしかないのでしょうか。


CC BY-SA 3.0
2016-07-14T12:09:49.063
27624
2016-07-15T06:47:56.860
7232
question
go
Golang のスライスについて


今回の質問で取り上げたコードの場合、変数`objects`を呼び出し先`loadJSON`で変更したいわけですから`loadJSON(&objects,
src)`のようにポインタ渡しを利用するのが良いです。

[code]

    package main
    
    import (
        "encoding/json"
        "fmt"
    )
    
    type Object struct {
        Name string `json:"name"`
    }
    
    func loadJSON(objects *[]Object, src []byte) error {
        return json.Unmarshal(src, objects)
    }
    
    func main() {
        src := []byte(`[{"name":"Taro"}, {"name":"Hanako"}]`)
        var objects []Object
        if err := loadJSON(&objects, src); err != nil {
            panic(err)
        }
    
        fmt.Println(objects)
    
    }
    
[/code]

実行例: <https://play.golang.org/p/Zux4HzPRMd>


CC BY-SA 3.0
2016-07-14T14:59:36.587
27632
2016-07-14T14:59:36.587
2391
27624
answer


呼び出し側で宣言している配列(正確にはスライス)は `nil` であり実体を伴っていません。

[code]

    var object []Object
    
[/code]

この変数 `object` が nil になっており、そのため呼び出した先では要素を格納できず、仕方なくあたらしい配列を **作成**
しているのですが、呼び出し元へ返す方法ないために動作していないように見えるのです。

その証拠に、 `object := make([]Object, 2)` として、予め確保したものを渡す版を作ってみました。
<https://play.golang.org/p/F7HXHRfX7k> `object`
の宣言部分以外は変えていないのに意図通りの動作をすることを確認してください。

よって回答としては「プログラムが誤っており、配列を渡していないから」となります。また、このような使い方における書き方としては以下の3つが考えられます。

  1. 配列を予め確保して渡す
  2. 配列の変数のポインタを渡す (koshさん指摘の方法)
  3. 返り値を返す

しかし個人的には `append()`
と同じように、返り値を返すようにするのに加え、予め確保したものを引数へ渡せるようにするのが、良いパターンだろうなと考えています。


CC BY-SA 3.0
2016-07-14T23:57:05.393
27635
2016-07-15T06:47:56.860
2016-07-15T06:47:56.860
208
208
27624
answer