Goの基本型は、数値、真偽値、文字列です。どの変数もコンパイル時に決まるちょうど1つの型を持ち、Goが型を勝手に変換することはありません。%T はどんな値の型でも表示します。
'G' が型 int32 の 71 として表示されることに注目してください。シングルクォートで囲んだ文字はルーンで、ルーンは数値(Unicodeのコードポイント)です。rune は int32 の別名(同じ型に付けた2つ目の名前)なので、%T は int32 と表示します。同じように byte は uint8 と表示されます。
整数
| 型 | サイズ | 範囲 |
|---|---|---|
int8 | 8ビット | -128から127 |
int16 | 16ビット | -32,768から32,767 |
int32 | 32ビット | 約-21億から21億 |
int64 | 64ビット | 約-922京から922京 |
uint8(byte) | 8ビット | 0から255 |
uint16 | 16ビット | 0から65,535 |
uint32 | 32ビット | 0から約43億 |
uint64 | 64ビット | 0から約1844京 |
int、uint | 32または64ビット | プラットフォームのワードサイズ |
uintptr | プラットフォーム依存 | 低レベルのコード向けに、ポインタの値を保持する |
デフォルトでは int を使います。 len() は int を返し、スライスのインデックスも int、ループのカウンタも int です。64ビットのプラットフォームではどこでも int は64ビットです。サイズ付きの型を使うのは、サイズが取り決めの一部になっているときです。バイナリファイル形式の int32、生のバイトの uint8、ナノ秒単位のUnixタイムスタンプの int64 などです。
個数のように「負にならない」量に符号なし型を使うのは避けましょう。ゼロより下に引き算すると、検出できる負の数になるのではなく、巨大な数に折り返します。
上限とオーバーフロー
math パッケージには、すべての上限に対応する定数があります。実行時に整数の演算がオーバーフローすると、何も言わずに折り返します。
panicもエラーもなく、127 + 1 は -128 になります。コンパイル時にチェックされるのは定数式だけです(var b int8 = 128 はコンパイルできません)。データでオーバーフローが起こりうるなら、演算の前にチェックするか math/big を使います。
整数リテラル
million := 1_000_000 // underscores for readability (Go 1.13+)
mask := 0xFF // hexadecimal
perm := 0o755 // octal (also the older form 0755)
flags := 0b1010 // binary
浮動小数点数
| 型 | サイズ | 精度 |
|---|---|---|
float32 | 32ビット | 有効桁数 約6から9桁 |
float64 | 64ビット | 有効桁数 約15から17桁 |
小数点や指数を含むリテラル(2.5、1e6)はデフォルトで float64 になり、math パッケージも float64 を受け取って返します。大きな配列でメモリが問題にならない限り、これを使います。
浮動小数点数は2進数なので、ほとんどの10進の小数は近似値になります。
ここから2つのルールが導かれます。演算した後の浮動小数点数を == で比較してはいけません。そして、お金を浮動小数点数で保存してはいけません。セント単位の整数か、10進数のライブラリを使います。
浮動小数点数をゼロで割ると、panicせずに +Inf、-Inf、NaN になります。整数 をゼロで割ると実行時にpanicし(runtime error: integer divide by zero)、定数のゼロで割るとコンパイルエラーになります。
真偽値
bool は true か false を保持し、ゼロ値は false です。Goは数値、空文字列、nil を真偽値として扱いません。if count {} はコンパイルエラーで、if count > 0 {} と書きます。演算子は &&、||、! で、&& と || は短絡評価されます。
文字列
string は変更できないバイトの並びで、通常はUTF-8のテキストです。len(s) は文字数ではなくバイト数を数えます。
é はUTF-8で2バイトを使うので、5文字に対して len は6を返します。ダブルクォートの文字列は \n のようなエスケープを処理しますが、バッククォートの生文字列は処理せず、複数行にまたがれます。strings パッケージは文字列のページで、UTF-8の詳細はルーンとバイトのページで扱っています。
byteとrune
| 別名 | 実体 | 保持するもの |
|---|---|---|
byte | uint8 | 生データの1バイト |
rune | int32 | Unicodeのコードポイント1つ |
これらは新しい型ではなく別名です。byte と uint8 は変換なしで相互に使えます。名前は、その数値が何を意味するかを表しています。
複素数
Goには組み込みの複素数型 complex64 と complex128 があり、real、imag、そして math/cmplx パッケージで扱います。
必要とするプログラムは多くありませんが、信号処理や一部の数値計算のコードでは使われます。
複合型と参照型
基本型を組み合わせると複合型になります。それぞれに専用のページがあります。
| 型 | 例 | ゼロ値 |
|---|---|---|
| 配列 | [3]int | 3つのゼロ |
| スライス | []int | nil |
| マップ | map[string]int | nil |
| 構造体 | struct{ X, Y int } | すべてのフィールドがゼロ値 |
| ポインタ | *int | nil |
| 関数 | func(int) int | nil |
| チャネル | chan int | nil |
| インターフェース | error、any | nil |
any は interface{} の別名で(Go 1.18以降)、どんな型の値でも保持できます。
名前付きの型
既存の型から新しい型を定義できます。表現は同じですが別の型であり、メソッドを持てます。
type Celsius float64
type UserID int64
var t Celsius = 21.5
var f float64 = t // compile error: cannot use t (variable of float64 type Celsius) as float64 value in variable declaration
この厳しさこそが狙いです。OrderID が必要な場所に、うっかり UserID を渡すことはできません。意図しているときは明示的に変換します:float64(t)。ルールは型変換のページを、数値と文字列の相互変換は strconv の関数を参照してください。
ゼロ値
どの型にもゼロ値があり、何も代入する前の変数はそれを保持しています。数値は 0、bool は false、文字列は ""、ポインタ、スライス、マップ、チャネル、関数、インターフェースは nil です。Goに初期化されていない変数はありません。
よくある質問
Goのintは何ビットですか?
int と uint は、64ビットのプラットフォーム(amd64、arm64)では64ビット、32ビットのプラットフォームでは32ビットです。ファイル形式やネットワークプロトコルなどで固定のサイズが必要なら、int32、int64、uint8 などを使います。普通のカウンタ、インデックス、長さには int を使います。
Goで変数の型を表示するには?
%T 書式指定子を使います:fmt.Printf("%T\n", x) は int、float64、[]string、main.User などを表示します。コードの中では、reflect.TypeOf(x) が同じ情報を調べられる値として返します。
Goのbyteとruneの違いは何ですか?
byte は uint8 の別名で、生データの1バイトを保持します。rune は int32 の別名で、Unicodeのコードポイント1つを保持します。文字列はバイトの並びで、for range で走査するとルーンにデコードされます。
Goではfloat32とfloat64のどちらを使うべきですか?
理由がない限り float64 を使います。浮動小数点数リテラルのデフォルトの型であり、math パッケージが扱う型であり、有効桁数は10進で約15から17桁あります(float32 は約6から9桁)。float32 を選ぶのは、大きな配列でメモリを半分にしたいときか、外部の形式に合わせるときだけです。
Goのintの最大値はいくつですか?
math パッケージの定数を使います:math.MaxInt(64ビットのプラットフォームでは9223372036854775807)、math.MinInt、math.MaxInt64、math.MaxUint32 などです。上限を超える演算は実行時に何も言わずに折り返し、panicはしません。