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

Goでsliceをappendすると予想と違う動作をするらしい

はじめに

こんにちはRIN1208です。今回はITRCアドベントカレンダーの二日目の記事です。

今回書くのは本日12月2日に六本木ヒルズで行われたStep up Go で初めて知って今後もハマりそうなことを勉強しましたので忘れないように書いていきたいと思います。

実行環境はplay.golangを使用します(なぜかmacだと問題を再現できませんでした)

今回の問題

package main

func main() {
    a := []int{1, 2, 3}
    b := append(a, 4, 5)
    a[0] = 10
    c := append(b, 6, 7)
    b[1] = 20
    println(c[0] + c[1])
}

こちらのコードです。

実行すると....

21

は??????

なんで???3じゃないの?と思いました。普通ポインタとスライスの中身を見てみると

package main

import "fmt"

func main() {
    a := []int{1, 2, 3}
    b := append(a, 4, 5)
    a[0] = 10
    c := append(b, 6, 7)
    b[1] = 20

    println("%p", a)
    println("%p", b)
    println("%p", c)

    fmt.Println(a, b, c)

    println(c[0] + c[1])
}

出力結果

%p [3/3]0x40e020
%p [5/8]0x456000
%p [7/8]0x456000
[10 2 3] [1 20 3 4 5] [1 20 3 4 5 6 7]
21

bとcが同じポインタ??????

goのsliceはこちらのような構造になっているらしいです。

また同じポインタを参照しているので反映されてしまっているみたいです。

ちなみにcapを更新?するとポインタも変わるみたいです

package main

import "fmt"

func main() {
    a := []int{1, 2, 3}
    b := append(a, 4, 5)
    a[0] = 10
    c := append(b, 6, 7)
    b[1] = 20
    d := append(c, 6, 7)
    c[1] = 30

    println("%p", a)
    println("%p", b)
    println("%p", c)
    println("%p", d)

    fmt.Println(cap(a), cap(b), cap(c), cap(d))
    fmt.Println(a, b, c, d)

    println(c[0] + c[1])
}
----------------------------

%p [3/3]0x40e020
%p [5/8]0x456000
%p [7/8]0x456000
%p [9/16]0x430080
3 8 8 16
[10 2 3] [1 30 3 4 5] [1 30 3 4 5 6 7] [1 20 3 4 5 6 7 6 7]
31

結論

goの配列は途中保存するときは上記の書き方ではなくcopy関数を使用し別の変数に格納した方がいいみたいです

終わりに

今回、自分の未熟さゆえに曖昧な部分が多いのに加え適切な言い方ではない箇所があるためとてもいい記事ではないと思います。ですが今回初めてこんな挙動をすると知ったので知らない人に知っていただければと思い書きました。また本記事について詳しく知っている方はコメントにて教えて頂けるととても助かります。

Why not register and get more from Qiita?
  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
No 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
ユーザーは見つかりませんでした