Golangにはスライスってものがあるようです。
JavaでいうとArrayListに当たるのかな?
可変長配列らしいです。
初期化の方法としては、最初から値を入れるパターンと、入れないパターンとあると思うのですけど。
/* 初期値ありの場合 */
retArray := []string{"a", "b"}
/* 初期値なしの場合 */
retArray := make([]string, 0, 0)
問題は、この「make」の引数。
公式を探そうにも、どう探したらいいかがよくわからない、、、
っていうか、GolangのAPI見にくい。。。
ってわけで、自分でいろいろ検証してみました。
#定義
参考にした元記事にはこんな感じに書いてました。
スライスは配列へのポインタ、長さ、キャパシティの3つの情報から構成されている。長さは要素数で、キャパシティはスライスの最初の要素から数えたときの参照先の配列の要素数。長さ、キャパシティはそれぞれlen、cap関数で取得することができる。
https://qiita.com/rock619/items/db44507d02814e490902
変数名 := make([]入れる型(Generics的な?), len(長さ), cap(キャパシティ))
、、、正直、ちんぷんかんぷんです。
- lenは初期で作成される要素の数、capは確保される容量の数。
- len < cap になるような設定はダメ。(決められた容量を超えた要素は作れない)
- 容量を超えたデータを追加すると、元の倍の容量が自動で確保される。
#検証
len、capのところに、いろんな値を入れてみました。
で、デバッグで確かめてみたので、ちょっと見にくいですが、左がデバッグ、右がコードですー。
※ついでに、appendした時も見てみた。
make([]string, 0, 0)
make後
中身はなんもない。
append後
[0]に値が追加された。
make([]string, 0, 1)
make後
中身はなんもない。
append後
[0]に値が追加された?
make([]string, 0, 3)
make後
中身はなんもない。
append後
[0]に値が追加された?
make([]string, 2, 0)
make([]string, 2, 2)
make後
既に箱が作られてる。
append後
[2]に値が追加された。(次のインデックス?)
なんでcapが2増えたのか?については、直前のcapが「2」だったので、倍の「4」になったっぽい。
これはGo言語の仕様によるもので、容量オーバーしたら基本的に2倍(※追記参照)の値を確保します。
appendするたびに一々メモリ領域を確保してコピーする手順を踏むのは効率が悪いため
このような動作になっています。
https://qiita.com/Kashiwara/items/e621a4ad8ec00974f025
######2019/11/15 追記 (c-yan様、ありがとうございます!)
正確には1024未満の時は2倍、それ以上の時は1.25倍とのことです。
ソース見たら、確かに。。。ソースもちゃんと見て仕様確認しないとですね
https://github.com/golang/go/blob/master/src/runtime/slice.go#L100
ただ、このソースの「func growslice」がどこから呼ばれてるのか、はまだ確認中です。。。
appendで呼ばれてそうな気もするんだけど、、、実装が見つからない。。。
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
make([]string, 2, 3)
検証のため、やってみた。
makeでは、要素2で作られた。
1個の用を追加したけど、容量内なので、capはそのまま
もう1個追加したことで、容量オーバーに。
で、元の容量の倍の「6」が容量に設定された。
#まとめ
使い方がなんとなくわかった。
capとかでメモリの管理もしているあたり、C言語がベース、って感じがする。
Javaらーにはまだまだ概念としてわかりにくい部分がきっとありそうだけど、
出会ったら検証していきますっ!