Skip to content

Latest commit

 

History

History
212 lines (154 loc) · 7.74 KB

4.03.md

File metadata and controls

212 lines (154 loc) · 7.74 KB

セクション 4.3 数値型

整数(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言語でのプログラミングはプログラミングを楽にするためにデザインされています。効率的なコンパイル、楽なプログラミング、効率的な実行です。ですから、単にintfloat64を使えばよいのです。

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)
}

playground

このケースでは、コンパイラはintfloat64がふさわしいと型を推測しています。

自分で型を指定してみましょう。

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)
}

playground

気をつけて欲しいポイントですが、:=を使って変数を再宣言すると、_変数シャドーイング_が起こってしまいます。なので=を使いましょう。

xintと宣言した後に浮動小数点数を割り当てようとすると、コンパイラはエラーを起こします。

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)
}

playground

Numberic Typesのドキュメントを見直してみましょう。int8uint8やその他の型がありますね。 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)
}

playground

同じように、127まで保存できます。128ではないです。

package main

import (
	"fmt"
)

var x int8 = 128 // 127でも試してください。

func main() {
	fmt.Println(x)
	fmt.Printf("%T\n", x)
}

playground

必要な変数に応じてより正確な型を選ぶことは良いことですが、精度をしっかり決めたくないときには、intfloat64を使いましょう。

intは特定のサイズを持った定義済みの型のセットです。

uint     32もしくは64bitsのuintセット
int      uintと同じサイズ
uintptr  ポインタを表すのに十分な大きさの符号なしint

32ビットマシンでなら32ビットで動作するように、コンパイラがプログラムによって32ビットか64ビットかが必要なのを判断してくれるので、intuintを使うのが良いでしょう。これはワードサイズと呼ばれます。コンピューターの_ワードサイズ_は01を同時にどれだけ扱えるかによります。

エイリアス

byteを除いて、すべての数値型は個々に分かれています。ただ、uint8のエイリアスのbyteint32のエイリアスのruneは違います。_byte_は8ビットだと覚えているでしょうか。なので、uint8byteとも呼べるようになっています。runeint32のエイリアスです。これは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)
}

playground

ランタイムパッケージ

GoDocのruntimeパッケージを見てみましょう。このパッケージを使えば、Goが実行されるOSやアーキテクチャに関する情報を見ることができます。

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Println(runtime.GOOS)
	fmt.Println(runtime.GOARCH)
}

playground

playgroundではnaclamd64p32という結果が出力されていると思います。Go playgroundはNaClで動いているからですね。amd64p32ではポインタは32ビットで、_ワードサイズ_は64ビットです。