JavaScriptを有効にしてください

Go言語で型のサイズを取得する方法

 · 

Go言語で型のサイズを取得する方法

C言語でいう所のsizeofはGo言語にあるんだろうか?🤔という所が気になったので調べてみました。

早速結論ですが、Go言語で型のサイズを取得する場合はunsafe.Sizeof関数を使用します。
では使い方を見ていきましょう。

unsafe.Sizeof関数を使って型のサイズを取得する

使い方はとても簡単で、Sizeof関数の引数にサイズを取得したい変数を指定してあげるだけです。

1
2
3
4
var a int

typeSize := unsafe.Sizeof(a)
fmt.Printf("unsafe.Sizeof関数で取得したint型のサイズ:%dバイト\n", typeSize)
1
unsafe.Sizeof関数で取得したint型のサイズ:8バイト

実行するとint型は8バイトという結果になりました。
ですがint型のサイズは環境に依存するため、4バイトや8バイトなどに変化することに注意してください。

ちなみにSizeof関数で取得するとuintptr型となっているため、演算で使用する時に不便です。
演算で使用したい場合はint型にキャストしてあげましょう。

1
2
3
arraySize := 8
totalSize := int(typeSize) * arraySize
fmt.Printf("要素数%d個のint配列のサイズ:%dバイト\n", arraySize, totalSize)
1
要素数8個のint配列のサイズ:64バイト

unsafe.sizeof関数については以上となります。

他にreflectを使用した取得方法もありますのでそちらも見ていきましょう。

reflect.TypeOf関数を使って型のサイズを取得する

こちらもunsafeのSizeof関数と同様に、Typeof関数の引数にサイズを取得したい変数を指定してSize関数を呼ぶだけです。

1
2
3
4
var b int

typeSize = reflect.TypeOf(b).Size()
fmt.Printf("reflect.TypeOf関数で取得したint型のサイズ:%dバイト\n", typeSize)
1
reflect.TypeOf関数で取得したint型のサイズ:8バイト

当然ながらどちらの関数を使用しても結果は一緒になります。
ただreflectの方は記述が長くなるため、短くてスッキリ見えるunsafeの方がいいと思います。

次は色々な型のサイズを調べて、想像と違ったものをピックアップしてみましたので見ていきましょう。

string型のサイズを調べてみる

string型のサイズがどういう結果になるのか見ていきましょう。

1
2
3
4
var c string

typeSize = unsafe.Sizeof(c)
fmt.Printf("string型のサイズ:%dバイト\n", typeSize)
1
string型のサイズ:16バイト

16バイト???🙃

何やら斜め上な結果が返ってきましたが、stringの実行時の実体は下記の構造体になっているようです。

1
2
3
4
type StringHeader struct {
	Data uintptr
	Len  int
}

参照:Go reflect StringHeader

構造体を指定すると各メンバのサイズの合計が返ってくるため、16バイトだったというオチですね。

次はスライスのサイズを見ていきましょう。

スライスのサイズを調べてみる

string型が構造体のサイズだったので、こちらも同じでは?という推測がたちますがどうでしょうか。

1
2
3
4
var d []int

typeSize = unsafe.Sizeof(d)
fmt.Printf("スライスのサイズ:%dバイト\n", typeSize)
1
スライスのサイズ:24バイト

推測した通り構造体のサイズになっているようです。
スライスの構造体は下記のとおりです。

1
2
3
4
5
type SliceHeader struct {
	Data uintptr
	Len  int
	Cap  int
}

参照:Go reflect SliceHeader

スライスに対してsizeof関数を使うとスライスの要素数に応じたサイズが返ってくると思いがちですが、残念ながら動的なサイズではなく静的なサイズが返されます。
ここらへんを勘違いしてしまう方は結構いそうです🙄

スライスのサイズはlenとcapで取得しましょうということですね。

では次に、もう想像がついてますが一応マップのサイズも見ていきましょう。

マップのサイズを調べてみる

1
2
3
4
var e map[string]int

typeSize = unsafe.Sizeof(e)
fmt.Printf("マップのサイズ:%dバイト\n", typeSize)
1
マップのサイズ:8バイト

想像どおりでした🙂

恐らくマップの構造体のポインタのサイズになっていますね。

マップの実装は複雑なので、興味のある方はソースコード を見て頂ければと思います。

まとめ

いかがでしたか。

私はsizeof関数を通して、内部の実装についてより理解が深まりました。
Go言語ではあまり使う機会がないと思いますが、どういうものか理解しておくと後々役に立つこともあると思うのでぜひ色々調べてみて下さい。

プログラム全体

コピーしてGo Playground に貼り付ければ実行できますので、実際の動作を確認してみてください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

func main() {
	//---------------------------------------------------------
	// unsafe.Sizeof関数を使って型のサイズを取得する
	//---------------------------------------------------------
	var a int

	typeSize := unsafe.Sizeof(a)
	fmt.Printf("unsafe.Sizeof関数で取得したint型のサイズ:%dバイト\n", typeSize)
	// uintptr型をint型にキャスト
	arraySize := 8
	totalSize := int(typeSize) * arraySize
	fmt.Printf("要素数%d個のint配列のサイズ:%dバイト\n", arraySize, totalSize)
	//---------------------------------------------------------
	// reflect.TypeOf関数を使って型のサイズを取得する
	//---------------------------------------------------------
	var b int

	typeSize = reflect.TypeOf(b).Size()
	fmt.Printf("reflect.TypeOf関数で取得したint型のサイズ:%dバイト\n", typeSize)
	//---------------------------------------------------------
	// string型のサイズを調べてみる
	//---------------------------------------------------------
	var c string

	typeSize = unsafe.Sizeof(c)
	fmt.Printf("string型のサイズ:%dバイト\n", typeSize)
	//---------------------------------------------------------
	// スライスのサイズを調べてみる
	//---------------------------------------------------------
	var d []int

	typeSize = unsafe.Sizeof(d)
	fmt.Printf("スライスのサイズ:%dバイト\n", typeSize)
	//---------------------------------------------------------
	// マップのサイズを調べてみる
	//---------------------------------------------------------
	var e map[string]int

	typeSize = unsafe.Sizeof(e)
	fmt.Printf("マップのサイズ:%dバイト\n", typeSize)
}
1
2
3
4
5
6
unsafe.Sizeof関数で取得したint型のサイズ:8バイト
要素数8個のint配列のサイズ:64バイト
reflect.TypeOf関数で取得したint型のサイズ:8バイト
string型のサイズ:16バイト
スライスのサイズ:24バイト
マップのサイズ:8バイト

実行環境

1
2
$ go version
go version go1.18 linux/amd64

スポンサーリンク

共有

もふもふ
著者
もふもふ
プログラマ。汎用系→ゲームエンジニア→Webエンジニア→QAエンジニア