質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.64%

Go言語「A Tour of Go」のsliceでわからないことがあります

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 949
退会済みユーザー

退会済みユーザー

A Tour of GoでGo言語を学習中、sliceで理解できないところがありました。

「More types: structs, slices, and maps.」の「Slice length and capacity」という項目です。

以下がそのコードです。


package main

import "fmt"

func main() {
s := []int{2, 3, 5, 7, 11, 13}    //⑴
printSlice(s)    //(1)

// Slice the slice to give it zero length.
s = s[:0]    //⑵
printSlice(s)    //⑵

// Extend its length.
s = s[:4]    //⑶
printSlice(s)    //⑶

// Drop its first two values.
s = s[2:]    //⑷
printSlice(s)    //⑷
}

func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}


で、実行結果がこれです。

len=6 cap=6 [2 3 5 7 11 13]  //⑴
len=0 cap=6 []         //⑵
len=4 cap=6 [2 3 5 7]     //⑶
len=2 cap=4 [5 7]       //⑷

コードの⑴、⑵、⑷は理解できます。
(3)がわかりません。

(1)変数sを定義し、lengthが6、capacityが6のsliceをsに代入する。sは[2 3 5 7 11 13]。

(2)sを[:0]でスライスして、sに再代入する。lengthが0、capacityが6になる。sは[]。

(3)sを[:4]でスライスして、sに再代入する。
疑問:⑵でsliceのlengthが0になりました。そのsliceを[:4]でスライスして、なぜ実行結果が len=4 cap=6 [2 3 5 7] になるんでしょうか?なぜ中身が復活してくるのでしょうか?

(4)sを[2:]でスライスして、sに再代入する。lengthが2、capacityが4になる。sは[5 7]。

(2)のコードがなく、(1)→(3)→(4)の順に実行されていれば理解できるのですが...
教えていただけると幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

スライスは、

  • 実体の配列(C言語の配列と同じ概念)
  • どの区間にアクセスするのかを示すメタデータ

という二重管理の仕組みになっています。

詳しくはこちらを参照してください。

https://blog.golang.org/go-slices-usage-and-internals

メタデータは以下の三要素

  • 配列の要素へのポインタ
  • スライス長
  • 配列の容量

配列の容量が不足したら新しい配列を大きなサイズでメモリ確保して
元データ参照範囲をコピーします。
ポインタは新しい配列の先頭を指すように変更されます。
質問の例では容量が不足していないのと実体の内容が変更されていないため
以前のデータが復活したかの様になるのです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/31 23:14

    ご回答ありがとうございます!

    参照URLを確認しました。
    ものすごく説明が分かりやすくて
    sliceの概念を理解することができました。

    また、参照URLを読みつつ、
    A Tour of Goのコードを下記コードに書き換えてみたところ、
    疑問に思っていたことが腑に落ちました。

    package main

    import "fmt"

    func main() {
    s := []int{2, 3, 5, 7, 11, 13, 15}
    printSlice(s)

    s = s[2:5]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Extend its length.
    s = s[:5]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)
    }

    func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
    }

    //実行結果
    len=7 cap=7 [2 3 5 7 11 13 15]
    len=3 cap=5 [5 7 11]
    len=4 cap=5 [5 7 11 13]
    len=5 cap=5 [5 7 11 13 15]
    len=3 cap=3 [11 13 15]

    ご親切にありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る