整数(Integer)と浮動小数点数(floating point)については既に話してきました。何が違うのでしょう?Integerはdecimalを含んでいません。しかしそれらは_全部_、数値と呼ばれるのです。
_浮動小数点数_はdecimalを含む数値です。そしてこれらはともに_実数_とも呼ばれます。
go specでは、Numeric Types(数値型)というセクションがあります。
+uint8 符号なし8bit整数セット (0 to 255)
+uint16 符号なし16bit整数セット (0 to 65535)
+uint32 符号なし32bit整数セット (0 to 4294967295)
+uint64 符号なし64bit整数セット (0 to 18446744073709551615)
+
+int8 符号あり8bit整数セット (-128 to 127)
+int16 符号あり16bit整数セット (-32768 to 32767)
+int32 符号あり32bit整数セット (-2147483648 to 2147483647)
+int64 符号あり64bit整数セット (-9223372036854775808 to 9223372036854775807)
+
+float32 IEEE-754 32bit浮動小数値セット
+float64 IEEE-754 64bit浮動小数値セット
+
+complex64 float32の実数部と虚数部を持つ複素数
+complex128 float64の実数部と虚数部を持つ複素数
+
+byte uint8の別名
+rune int32の別名
uint 32もしくは64bitsのuintセット
int uintと同じサイズ
uintptr ポインタを表すのに十分な大きさの符号なしint
全ての型を使わないといけないのでしょうか?答えは「使いたいなら」です。
無駄なビットを使いたくないとか、10億ユーザーを扱わなければいけないとか、何10億回も何TBものデータを扱うとか、正確な精度が必要であれば最もふさわしい型を選ぶ必要があるでしょう。そのようなケースでは、格納できるうちで最も小さい型を選ぶべきでしょう。
全体的にですが、Go言語でのプログラミングはプログラミングを楽にするためにデザインされています。効率的なコンパイル、楽なプログラミング、効率的な実行です。ですから、単にint
とfloat64
を使えばよいのです。
package main
import (
"fmt"
)
func main() {
x := 42
y := 42.34534
fmt.Println(x)
fmt.Println(y)
fmt.Printf("%T\n", x)
fmt.Printf("%T\n", y)
}
このケースでは、コンパイラはint
とfloat64
がふさわしいと型を推測しています。
自分で型を指定してみましょう。
package main
import (
"fmt"
)
var x int
var y float64
func main() {
x = 42
y = 42.34534
fmt.Println(x)
fmt.Println(y)
fmt.Printf("%T\n", x)
fmt.Printf("%T\n", y)
}
気をつけて欲しいポイントですが、:=
を使って変数を再宣言すると、_変数シャドーイング_が起こってしまいます。なので=
を使いましょう。
x
をint
と宣言した後に浮動小数点数を割り当てようとすると、コンパイラはエラーを起こします。
package main
import (
"fmt"
)
var x int
var y float64
func main() {
x = 42.34534
y = 42.34534
fmt.Println(x)
fmt.Println(y)
fmt.Printf("%T\n", x)
fmt.Printf("%T\n", y)
}
Numberic Typesのドキュメントを見直してみましょう。int8
やuint8
やその他の型がありますね。 u
は_符号なし_の意味です。_符号あり_とは-
や+
から始まる数字です。_符号なし_の場合は、0
以上の数のみです。
8bitの場合、int8
か、uint8
で256個の数字を保存できます。8ビットでは洗わせるのは2の8乗、つまり256です。2, 4, 8, 16, 32, 64, 128, 256ですね。でも、保存できるのは255
までなのはなぜでしょう?0があるからです。0
, 1
, 2
, 3
, 4
, 5
, 6
, 7
, 8
, 9
が最初の10個の数字です。
int8
でも同じように、0
を含む-128
から127
の256個の値を保存できます。
int8
に保存できるのは-128
からです。-129
ではないですよ。
package main
import (
"fmt"
)
var x int8 = -129 // -128でも試してください
func main() {
fmt.Println(x)
fmt.Printf("%T\n", x)
}
同じように、127
まで保存できます。128
ではないです。
package main
import (
"fmt"
)
var x int8 = 128 // 127でも試してください。
func main() {
fmt.Println(x)
fmt.Printf("%T\n", x)
}
必要な変数に応じてより正確な型を選ぶことは良いことですが、精度をしっかり決めたくないときには、int
かfloat64
を使いましょう。
int
は特定のサイズを持った定義済みの型のセットです。
uint 32もしくは64bitsのuintセット
int uintと同じサイズ
uintptr ポインタを表すのに十分な大きさの符号なしint
32ビットマシンでなら32ビットで動作するように、コンパイラがプログラムによって32ビットか64ビットかが必要なのを判断してくれるので、int
かuint
を使うのが良いでしょう。これはワードサイズと呼ばれます。コンピューターの_ワードサイズ_は0
と1
を同時にどれだけ扱えるかによります。
byte
を除いて、すべての数値型は個々に分かれています。ただ、uint8
のエイリアスのbyte
とint32
のエイリアスのrune
は違います。_byte_は8ビットだと覚えているでしょうか。なので、uint8
はbyte
とも呼べるようになっています。rune
はint32
のエイリアスです。これは32個の0と1を意味します。つまり、rune
はGoがUTF-8のエンコーディングスキーマを使って文字を表しているということです。
UTF-8はKen ThompsonとRob Pikeによって作られました。彼らはGo言語の作者でもあります。UTF-8は最も有名なコーディングスキーマで、文字によりますが、1から4バイトで文字を表します。世界中の言語の文字を収録しています。UTF-8の最初の部分はASCIIです。
UTF-8での文字は4byteまでのサイズになりえて、1バイトは8ビットです。なので、1文字に32ビット必要で、rune
は文字であり、int32
のエイリアスなのです。
package main
import (
"fmt"
)
var x byte = 127
var y rune = 2147483647
func main() {
fmt.Println(x)
fmt.Println(y)
fmt.Printf("%T\n", x)
fmt.Printf("%T\n", y)
}
GoDocのruntimeパッケージを見てみましょう。このパッケージを使えば、Goが実行されるOSやアーキテクチャに関する情報を見ることができます。
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println(runtime.GOOS)
fmt.Println(runtime.GOARCH)
}
playgroundではnaclとamd64p32
という結果が出力されていると思います。Go playgroundはNaClで動いているからですね。amd64p32
ではポインタは32ビットで、_ワードサイズ_は64ビットです。