SlideShare a Scribd company logo
Go言語のスライスを
  理解しよう
 2012/08/25 GDG Kobe
自己紹介
• 河本 泰孝 @yasi_life → @kwmt27
• 私とGo言語との関わり
  • 2011年のDevQuizで初めて触った
  • 2012年1月のGo言語勉強会に参加
  • 2012年4月の東海GTUGさんのGAE
  勉強会でGoを使った
自己紹介
• 最近では公式サイトの
  • Writing Web Applications
  • Go Slices
 を翻訳してみたり。
 https://github.com/
 kwmt/golangwiki/wiki
自己紹介
ということで、
• 1月のGo言語勉強会では
 スライスまで出来なくて、
• 自分でスライスについて翻訳してみた
 ので
公式サイトのGo Slicesを元に発表させて
頂きます。
もくじ
もくじ

1.かるく復習
2.Go言語の配列とは?
3.スライスとは?
(1)特徴
(2)内部構造
(3)拡張する
(4)削除する
進め方
説明しながら、実際に動きを確かめるデモを
していきたいと思います。
もし可能なら下記のサイトで動かせるので一
緒に動かして行きましょう。
http://play.golang.org/

でもそこまでガッツリやって頂く時間がない
かもしれません。半ハンズオン的な感じです
す。
ソース場所:https://github.com/kwmt/
1.かるく復習

変数宣言のいろいろ
 var a int = 1 // int型
 a := 1

標準出力するには
 import “fmt”
 fmt.Printf(“a=%d¥n”, a)

      デモ slice_0.go
2.Go言語の配列とは?
配列の定義方法


長さ(length) と要素の型を指定

var a [4]int
配列の定義方法


長さ(length) と要素の型を指定

var a [4]int

   長さ
 (length)
配列の定義方法


長さ(length) と要素の型を指定

var a [4]int

   長さ          要素の型
 (length)
配列の特徴
  a[n]はn番目の要素にアクセス可能
//配列宣言
var a [4]int
//0番目の要素に1を代入
a[0] = 1
//変数iを宣言してa[0]をiに代入
i := a[0]
// 表示すると
// i = 1
          デモ slice_1.go
配列の特徴

 明示的な初期化は不要
 (自動的に0で初期化されています)

前ページの例の0番目の要素以外は
値0となっています。
// a[0]==1,a[1]==0,a[2]==0,a[3]==0


          デモ slice_1.go
配列の特徴
配列変数は配列全体を表しています。
つまりC言語のように、先頭の配列要素へ
のポインタではありません。
イメージ
配列の特徴
 配列リテラルの書き方
・要素数を指定する
b := [2]string{“Penn”,”Teller”}

・要素数を指定しない
 (コンパイラに数えさせる)
b := [...]string{“Penn”,”Teller”}

          デモ slice_1.go
3.スライスとは?
スライスの定義方法


長さ(length) と要素の型を指定

var a []int

   長さ
 (length)     要素の型
スライスの定義方法


長さ(length) と要素の型を指定

var a []int

   長さ
 (length)     要素の型
(1)スライスの特徴

 スライスリテラルの書き方

letters := []string{“a”,”b”,”c”,”d”}


要素数の指定以外は、
配列リテラルの書き方と同じ
(1)スライスの特徴

組み込み関数 makeを
使ってスライスを作成できる。
(1)スライスの特徴
         make関数とは

make関数の書式

func make([]T, len, cap) []T

T:要素の型
len:長さ(length)
cap:容量(capacity)(オプション)
(1)スライスの特徴
          make関数とは

make関数は、スライス型のオブジェク
トを確保し、初期化する。

1番目の引数の型と同じ型を返す。

ポインタを返すわけではない。

 func make([]T, len, cap) []T
(1)スライスの特徴

make関数を使って
スライスを作成する例
var s []byte
s = make([]byte, 5, 5)
// s=[0 0 0 0 0]
// sの型=[]uint8

       デモ slice_2.go
(1)スライスの特徴

容量(capacity)は省略できる
var s []byte
s = make([]byte, 5, 5)

      次のように簡略化できる

s := make([]byte, 5)

※容量を省略すると、長さ=容量となる

        デモ slice_2.go
(1)スライスの特徴
スライスの長さ(length)と
容量(capacity)を
調べるには、組み込み関数のlenと
capを使用する。

len(s) // == 5
cap(s) // == 5

        デモ slice_2.go
(1)スライスの特徴
     スライスのゼロ

初期化さてないスライスの値:nil

スライス==nilならば、
  len,cap関数は0を返す




     デモ slice_2.go
(1)スライスの特徴
               re-slice

 再スライス化可能

b := []byte{‘g’,’o’,’l’,’a’,‘n’,’g’}
c := b[1:4]
// c=[]byte{’o’,’l’,’a’}
// スライスcはスライスbと同じメモリ領域



          デモ slice_2.go
(1)スライスの特徴
     re-slice


 b[1:4]




 デモ slice_2.go
(1)スライスの特徴
     re-slice


 b[1:4]




 デモ slice_2.go
(1)スライスの特徴
     re-slice


 b[1:4]


これら2つの数字は
  省略可能


 デモ slice_2.go
(1)スライスの特徴
            re-slice


b[:]

b[:2]

b[2:]
        デモ slice_2.go
(1)スライスの特徴
              re-slice


b[:]    ==b

b[:2]

b[2:]
        デモ slice_2.go
(1)スライスの特徴
              re-slice


b[:]    ==b

b[:2]   ==[]byte{‘g’,’o’}

b[2:]
        デモ slice_2.go
(1)スライスの特徴
              re-slice


b[:]    ==b

b[:2]   ==[]byte{‘g’,’o’}

b[2:]   ==[]byte{‘l’,’a’,’n’,’g’}

        デモ slice_2.go
(1)スライスの特徴
         re-slice




自分のコードで、s[:len(s)]
と再スライスしてたよ、、、へへ。

     デモ slice_2.go
(1)スライスの特徴
        re-slice

配列からスライスを作る




    デモ slice_2.go
(1)スライスの特徴
                  re-slice

  配列からスライスを作る


x := [3]string{"Лайка", "Белка", "Стрелка"}
s := x[:] // スライスsはxの記憶領域を参照




             デモ slice_2.go
(2)スライスの内部構造
スライスは、配列内の連続した領域への    イメージ
参照であり、以下の3つから構成される。

๏配列へのポインタ
๏セグメントの長さ(length)
๏容量(capacity)
 (セグメントの最大の長さ)
(2)スライスの内部構造

s := make([]byte,5)
イメージ




       デモ slice_3.go
(2)スライスの内部構造

s = s[2:4]
イメージ




       デモ slice_3.go
(2)スライスの内部構造

再スライスされた要素を変更すると、
元のスライスの要素も変更される。
d :=   []byte{'r', 'o', 'a', 'd'}
e :=   d[2:]
// e   == []byte{'a', 'd'}
e[1]   == 'm'
// e   == []byte{'a', 'm'}
// d   := []byte{'r', 'o', 'a', 'm'}

            デモ slice_3.go
(2)スライスの内部構造

len < cap の場合、lenをcapまで拡張できる
s = s[:cap(s)]
イメージ




       デモ slice_3.go
(2)スライスの内部構造

容量を超えて拡張できない。
(2)スライスの内部構造

容量を超えて拡張できない。



容量を増やせば、拡張できる。
(3)スライスを拡張する
      copyとappend関数


容量(capacity)を増やすには、

1.新しく大きな容量のスライスを作成

2.その新しいスライスに元のスライスの
内容をコピーする
(3)スライスを拡張する
         copyとappend関数

s := make([]byte, 5)
t := make([]byte, len(s),
                (cap(s)+1)*2)
for i := range s {
    t[i] = s[i]
}
s = t

          デモ slice_4.go
(3)スライスを拡張する
         copyとappend関数

s := make([]byte, 5)
t := make([]byte, len(s),
                (cap(s)+1)*2)
for i := range s {
    t[i] = s[i]
}
s = t

          デモ slice_4.go
(3)スライスを拡張する
        copyとappend関数

 copy関数を使って次のように書ける
s := make([]byte, 5)
t := make([]byte, len(s),
               (cap(s)+1)*2)
copy(t, s)
s = t

         デモ slice_4.go
(3)スライスを拡張する
        copyとappend関数

 書式は下記の通り
func copy(dst, src []T) int

 処理内容は、元のスライスから先のス
 ライスにデータをコピーする

 コピーした要素数を返す
(3)スライスを拡張する
       copyとappend関数

copy関数は異なるlengthのスライス
でもコピーできる
var a = [...]int{0, 1, 2, 3,
                  4, 5, 6, 7}
var s = make([]int, 6)
n1 := copy(s, a[0:])
//n1=6, s=[]int{0,1,2,3,4,5}
        デモ slice_4.go
(3)スライスを拡張する
     copyとappend関数

スライスにデータを追加するには、
append関数を使用する
(3)スライスを拡張する
       copyとappend関数

書式は下記の通り
func append(s []T, x ...T) []T

処理内容は、スライスsの最後に、
要素xを追加する

より大きな容量が必要なら(自動的に)拡張
してくれる
(3)スライスを拡張する
         copyとappend関数


s3   := make([]int,1)
//   s3 == []int{0}
//   cap(s3) == 1
s3   = append(s3, 1, 2, 3)
//   s3 == []int{0, 1, 2, 3}
//   cap(s3) == 4


          デモ slice_4.go
(3)スライスを拡張する
        copyとappend関数

 スライスにスライスを追加するには、
 ...を使用する
a := []string{“John”,”Paul”}
b := []string{"George",
              "Ringo", "Pete"}
a = append(a, b...)
//a == []string{"John", "Paul",
      "George", "Ringo", "Pete"}
         デモ slice_4.go
(4)スライスから削除する
スライスからある要素を削除するには

//例えば3を削除したい場合
s := []int{1, 2, 3, 4, 5}
s=append(s[:2],s[3:]...)
//s==[]int{1, 2, 4, 5}

※スライスに対しては、delete関数みたい
なものは用意されていません。
         デモ slice_5.go
(4)スライスから削除する
これだと容量は削除されない。
s = [1 2 3 4 5]
len(s)= 5 cap(s)=   5
アドレス:0x42120400
s = [1 2 4 5]
len(s)= 4 cap(s)=   5
アドレス:0x42120400

       デモ slice_5.go
(4)スライスから削除する
  ひとまず、削除関数を作っておきます。
func delete(i int, s []int) []int{
! s = append(s[:i], s[i+1:]...)
! return s
}
  これは先程のを関数にまとめただけ。
  もちろん容量は削除されない。
          デモ slice_5.go
(4)スライスから削除する
  容量を削除するには、このdelete関数内で
  再スライスした長さ分の スライスcを作り、
  作ったスライスに再スライスしたsをコピーします。

func delete(i int, s []int) []int{
! s = append(s[:i], s[i+1:]...)
! c := make([]int, len(s))
! copy(c, s)
! return c
}          デモ slice_5.go
最後に

Let’s enjoy Go life with Slice !

ご清聴ありがとうございました

More Related Content

Go言語のスライスを理解しよう

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. fmt.Printf(&amp;#x201C;a&amp;#x306E;&amp;#x578B;&amp;#xFF1A;%T&amp;#xA5;n&amp;#x201D;, a) //a&amp;#x306E;&amp;#x578B;&amp;#xFF1A; int\n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. a[0]=1\ni := a[0]\ni = 2\nfmt.Println(&quot;i=&quot;,i) // i=2\nfmt.Println(&quot;a[0]=&quot;,a[0]) // a[0]=1\n\n
  14. a[0]=1\ni := a[0]\ni = 2\nfmt.Println(&quot;i=&quot;,i) // i=2\nfmt.Println(&quot;a[0]=&quot;,a[0]) // a[0]=1\n\n
  15. a[0]=1\ni := a[0]\ni = 2\nfmt.Println(&quot;i=&quot;,i) // i=2\nfmt.Println(&quot;a[0]=&quot;,a[0]) // a[0]=1\n\n
  16. a[0]=1\ni := a[0]\ni = 2\nfmt.Println(&quot;i=&quot;,i) // i=2\nfmt.Println(&quot;a[0]=&quot;,a[0]) // a[0]=1\n\n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. a[0]=1\ni := a[0]\ni = 2\nfmt.Println(&quot;i=&quot;,i) // i=2\nfmt.Println(&quot;a[0]=&quot;,a[0]) // a[0]=1\n\n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n