【Go】コンポジット型
いわゆる、配列、Map的な型を総称して、コンポジット型と呼ばれている。
まぁ基本中の基本になる存在なので覚えておくと良い。
1. 配列
Goの配列は 静的サイズ を持つ値型。宣言時にサイズが確定し、後から変更できない。
実体は、宣言した要素数以上を持てないのが鉄則。基本中の基本。
宣言した配列の要素数より大きいindexに値を入れようとするとpanic: index out of rangeが起きる。
サイズは型の一部なので、[3]intと[5]intは別の型。
値型なので、代入や関数渡しで全体がコピーされる。
配置領域は、基本的にはスタック領域だが、エスケープ解析などでヒープに配置されることあり。 固定長なので、以下のようなことはできない。
code: go
s = append(s, 4)
appendは、スライス型のみを受け付ける
2. スライス
可変長の配列的なデータ構造で参照型として扱われる。
内部構造: {ptr: 配列へのポインタ, len: 長さ, cap: 容量}。
スライスヘッダーと呼ぶ。
内部にポインタを持つ。参照型と言われる所以。
ポインタ先の実体は、基本的にはヒープ領域にある。
ゼロ値はnil。参照系の型は基本的にnil。
nilだとしても、appendやlen, rangeは安全に利用可能。
append時に、容量(cap)がオーバーした場合は、新しい配列がヒープ領域上に確保され、そのpointerを指すslice返される。
代入や関数渡しでは、スライスヘッダーのみコピーされる。
3. マップ
キーと値のペアを格納するデータ構造で参照型。
内部はハッシュテーブルとして実装され、ヒープに配置される。
変数に確保されるのは、実体であるテーブルへのpointerだけ。
ゼロ値はnil。
nilマップから読み取りは可能(ゼロ値が返る)が、書き込みはパニック。
使用前に必ずmakeまたはリテラルで初期化が必要。
代入や関数渡しではポインタのみコピー、実データは共有。
要素が増えると自動的に内部で再ハッシュ化される。
make時に容量を設定でき、それ以上入れる場合は自動で再ハッシュ化
4. 構造体
異なる型のフィールドをまとめた複合型で値型。
フィールドは連続したメモリ領域に配置される(パディングあり)。
ゼロ値は各フィールドがそれぞれの型のゼロ値で初期化された構造体。
代入や関数渡しで全体がコピーされる。
配置場所はエスケープ解析次第(スタックまたはヒープ)。
Tips:
大きな構造体はポインタで渡すのが一般的(コピーコスト削減)。