TL;DR
- Go の事前宣言された型(predeclared type)とは組み込み型のことで、数値・rune・文字列のリテラルにはそれぞれ書き方とデフォルトの型がある。
- Go は暗黙の型変換をせず、整数演算のオーバーフローも検査しない。実行時に計算した値をイミュータブルにする方法もない。
内容
リテラル
整数と浮動小数点数のリテラルでは、0 から始まる数字は 8 進数になる。16 進数に p を付けると指数を表せる(例: 0x12.34p5 は 582.5)。デフォルトの型は、整数が int、浮動小数点数が float64 である。
rune リテラルは、1 文字の Unicode 文字('a')のほか、8 ビットの 8 進数(\141)、8 ビットの 16 進数(\x61)、16 ビットの 16 進数(\u0061)、32 ビットの Unicode(\U00000061)で書ける。デフォルトの型は rune である。
文字列リテラルには 2 種類ある。" で囲む解釈対象の文字列リテラル(interpreted string literal)では、\n などが改行として解釈される。` で囲むロー文字列リテラル(raw string literal)では、` 以外の文字をそのまま書ける。デフォルトの型は string である。
特別な整数型と整数型の選び方
byte は uint8 の別名、rune は 1 つのコードポイントを表す int32 の別名である。uintptr を使うと、C のようなポインタ操作ができる。
整数型は次のように選ぶ。特定の大きさと符号を持つ整数のバイナリファイルやネットワークプロトコルを扱うときは、対応する整数型を使う。すべての整数型で動くユーティリティ関数を書くときは、ジェネリクスを使う。それ以外は int を使う。
整数演算はオーバーフローを検査しない
Go の整数演算はオーバーフローを検査しない。そのため、次のコードは panic を起こさず、値がラップアラウンドする。
var b byte = 255
var smallI int32 = 2147483647
var bigI uint64 = 18446744073709551615
fmt.Println(b+1, smallI+1, bigI+1) // 0 -2147483648 0複素数・文字列
複素数の型には、実部と虚部に float32 を使う complex64 と、float64 を使う complex128 がある。リテラルは 1+2i のように書き、デフォルトの型は complex128 である。ゼロ値は 0 で、実部は real、虚部は imag で取り出す。
Go の文字列はイミュータブルなので、変数に入れた文字列の中身は変えられない。変数への再代入はできる。
型変換
Go は変数どうしの暗黙の型変換をしない。サイズの違う整数や浮動小数点数の間でも、明示的な変換が必要である。bool 以外の値を bool として扱うこともできない。
var x int = 10
var y float64 = 30.2
var sum1 float64 = float64(x) - y
var sum2 int = x + int(y)一方、Go のリテラルは型を持たない(untyped)ので、整数と浮動小数点数のリテラルどうしは演算できる。ただし、文字列リテラルを数値型の変数に代入できないなど、制限はある。
var x float64 = 200.3 * 5:= を避けるべきケース
:= による宣言は、次の場合には避ける。
- ゼロ値で初期化したいとき
- デフォルトの型が望む型と違うとき
- 新しい変数の宣言と既存の変数への代入が混ざるとき
3 つ目は、たとえば x, y := 30, "hello" で x が既存の変数の場合である。どれが新しい変数かを明確にするため、var で新しい変数を宣言し、= で代入する。
定数
Go の定数は、リテラルに名前を付けるもので、コンパイル時に決まる値しか持てない。代入できるのは、数値リテラル、true と false、文字列、rune、complex・real・imag・len・cap の結果、そしてそれらと演算子からなる式である。型の指定は任意で、指定しなければデフォルトの型が使われる。
定数はコンパイル時に計算され、副作用がなく、使われなければバイナリに含めないだけで済むので、使われなくてもコンパイルエラーにならない。パッケージレベルの変数も、使われなくてもコンパイルエラーにならない。定数の名前は XXX_XXX ではなく、Xxx や xxx が一般的である。
イミュータブルな値は作れない
Go には、実行時に計算した値をイミュータブルにする方法がない。そのため、イミュータブルな配列、スライス、マップ、構造体はなく、構造体のフィールドをイミュータブルと宣言することもできない。
キーワード
自分の理解
整数演算がオーバーフローを検査しないことは、初めて知った。では、どうやって検出するのか。math/bits を使えばできそうである。
sum, carry := bits.Add32(4294967295, 1, 0)
if carry == 1 {
fmt.Println("Overflow!")
}