LoginSignup
11
12

More than 1 year has passed since last update.

【備忘】Go 言語のデータ型と型変換

Last updated at Posted at 2021-09-05

備忘として、Go 言語の「データ型」と「型変換(キャスト)」についてまとめておきます。

1.Go 言語データ型一覧

データ型 サイズ 説明 値の範囲
uint8 1byte 符号無し整数 0 ~ 255
uint16 2byte 符号無し整数 0 ~ 65535
uint32 4byte 符号無し整数 0 ~ 4294967295
uint64 8byte 符号無し整数 0 ~ 18446744073709551615
int8 1byte 符号付き整数 -128 ~ 127
int16 2byte 符号付き整数 -32768 ~ 32767
int32 4byte 符号付き整数 -2147483648 ~ 2147483647
int64 8byte 符号付き整数 -9223372036854775808 ~ 9223372036854775807
float32 4byte 単精度浮動小数点数 有効桁数6桁の実数
float64 8byte 倍精度浮動小数点数 有効桁数14桁の実数
complex64 8byte 複素数 float32の実数部と虚数部を持つ複素数
complex128 16byte 複素数 float64の実数部と虚数部を持つ複素数
uint 4byte
8byte
符号無し整数 uint32 または uint64 と同じ
int 4byte
8byte
符号付き整数 int32 または int64 と同じ
uintptr (8byte) ポインタ型 PC環境により異なる
byte 1byte uint8のエイリアス 0 ~ 255
rune 4byte int32のエイリアス Unicodeのコードポイント1文字分を格納
string - 文字列型
bool 1byte 論理値型 true / false

<出典>
The Go Programming Language Specification

(サイズについての補足)
データ型に bit 数が表示されているもについては、サイズは自明です。
それ以外のデータ型のサイズを、手元の環境(Windows 64bit)で確認した結果は次のとおりでした。

main.go
package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var ui uint
    fmt.Printf("uint=%dbyte\n", unsafe.Sizeof(ui))

    var i int
    fmt.Printf("int=%dbyte\n", unsafe.Sizeof(i))

    var p uintptr
    fmt.Printf("uintptr=%dbyte\n", unsafe.Sizeof(p))

    var r rune
    fmt.Printf("rune=%dbyte\n", unsafe.Sizeof(r))

    var b bool
    fmt.Printf("bool=%dbyte\n", unsafe.Sizeof(b))
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
uint=8byte
int=8byte
uintptr=8byte
rune=4byte
bool=1byte

今は、ほとんどの PC が 64bit なので、大体同じ結果になるものと思います。

2.Go 言語のキャスト

キャストも簡単です。
int32 にキャストする場合は int32(キャストする変数)
float32 にキャストする場合は float32(キャストする変数)
というルールで書きます。

実際にコードで確認すると次のような感じです。

main.go
package main

import "fmt"

func main() {
    // int64 → int32
    var num64 int64 = 2147483647
    var num32 int32 = int32(num64)
    fmt.Printf("%T, %d\n", num32, num32) // int32, 2147483647

    // uint16 → uint64
    var unum16 uint16 = 65535
    var unum64 uint64 = uint64(unum16)
    fmt.Printf("%T, %d\n", unum64, unum64) // uint64, 65535

    // float64 → float32
    var f64 float64 = 123456.789876
    var f32 float32 = float32(f64)
    fmt.Printf("%T, %f\n", f32, f32) // float32, 123456.789062
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
int32, 2147483647
uint64, 65535
float32, 123456.789062

float64 から float32 にキャストすると、123456.789876 という数値が 123456.789062 というように、精度が落ちていることが確認できます。

2-1. 浮動小数点数から整数へのキャスト

浮動小数点数から整数型にキャストすると、小数点以下は切捨てとなるようです(以下のとおり)。

main.go
package main

import "fmt"

func main() {
    // float32 → int32
    var d32 float32 = 123.789
    var num32 int32 = int32(d32)
    fmt.Printf("%T, %d\n", num32, num32) // int32, 123
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
int32, 123

2-2. 符号あり変数と符号無し変数間のキャスト

uint8(符号無し整数)の値の範囲は 0 ~ 255 です。
int8(符号付き整数)の値の範囲は -128 ~ 127 です。
範囲の重複する 0 ~ 127 であれば、問題なくキャストできます。

範囲が重複しない 255 という数値が変数に格納されている場合に、キャストをすると次のようになります。

main.go
package main

import "fmt"

func main() {
    // uint8 → int8
    var unum8 uint8 = 255
    var num8 int8 = int8(unum8)
    fmt.Printf("%T, %d\n", num8, num8) // int8, -1
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
int8, -1

uint8 型の変数に入れている 255 という数値は、本来 int8 ではオーバーフローになるはずですが、エラーは起きず -1 という値で出力されています。
255-1 は値は見た目は違いますが、2進数にするとどちらも 11111111 を表しているため値自体は同一ということになります。

細かい説明は省略しますが、コンピュータで負の数を表す場合には、以下のように、その数値(2進数)に対応する2の補数が使用されるため、-1 は2進数で 11111111 と表現されるためです。

<-1 を二進数で表示する>
0000 0001  :  二進数で[1]を表示する
1111 1110  :  0000 0001 の1の補数
1111 1111  :  0000 0001 の2の補数(これが[-1]を表す)

<-5 を二進数で表示する>
0000 0101  :  二進数で[5]を表示する
1111 1010  :  0000 0101 の1の補数
1111 1011  :  0000 0101 の2の補数(これが[-5]を表す)

2-3. オーバーフローする場合のキャスト

元のサイズよりも小さいサイズのデータ型にキャストする場合には、オーバーフローとなる場合があります。
しかし、この場合もエラーは生じません。

main.go
package main

import "fmt"

func main() {
    // uint16 → uint8
    var unum16 uint16 = 258
    var unum8 uint8 = uint8(unum16)
    fmt.Printf("%T, %d\n", unum8, unum8) // uint8, 2
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
uint8, 2

uint16 では 258 であった変数を、uint8 にキャストすると 2 となります。
これは、キャストの結果により、下8桁分だけの値が取得されているためです。

<uint16に格納された値>
0000 0001 0000 0010  :  二進数で[258]を表示

<uint8に格納された値>
          0000 0010  :  uint8 へのキャストにより下8桁(8bit分)のみ取得される
                        結果として[2]が表示される。

3.文字列と数値の相互変換

「文字列から数値に変換する場合」及び「数値から文字列に変換する場合」は、strconv ライブラリを使用します。

3-1. 文字列から数値への変換

3-1-1. 一般的な変換

文字列から数値への変換は、Atoi 関数を使用します(atoi とは「ASCII to Integer」の意です)。
コードを書くと、次のようになります。

main.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    var numStr1 string = "2468"
    i, err := strconv.Atoi(numStr1)
    fmt.Println(i)   // 2468
    fmt.Println(err) // <nil>

    var numStr2 string = "2468yen" // 数字以外の文字が混じっている場合
    j, err := strconv.Atoi(numStr2)
    fmt.Println(j)   // 0
    fmt.Println(err) // strconv.Atoi: parsing "2468yen": invalid syntax
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
2468
<nil>
0
strconv.Atoi: parsing "2468yen": invalid syntax

Atoi 関数を使用すると2つの値が戻ってきます。
1つ目は、int 型で文字列を変換した数値が返されます。
2つ目は、エラーの内容が返されます。

数値以外の文字を変換しようとすると、エラーが生じます。
上記のコードで、"2468yen" という文字列を変換しようとすると、strconv.Atoi: parsing "2468yen": invalid syntax という構文エラーが表示され、数値としては 0 という値が返されています。

エラーの取得が不要な場合は、次のように err_ に置き換えます。

main.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    var numStr string = "12345678"
    var n int // あらかじめ変数を指定する場合はint型
    n, _ = strconv.Atoi(numStr)
    fmt.Println(n) // 12345678
}

なお、数値は int 型で返されますので、あらかじめ変数を指定する場合は int 型の変数としておきます。

3-1-2. 詳細な変換指定

main.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    b, _ := strconv.ParseBool("true")
    fmt.Printf("%T, %t\n", b, b) // bool, true

    f, _ := strconv.ParseFloat("3.1415", 64)
    fmt.Printf("%T, %f\n", f, f) // float64, 3.141500

    i, _ := strconv.ParseInt("-42", 10, 32)
    fmt.Printf("%T, %d\n", i, i) // int64, -42

    u, _ := strconv.ParseUint("42", 10, 16)
    fmt.Printf("%T, %d\n", u, u) // uint64, 42
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
bool, true
float64, 3.141500
int64, -42
uint64, 42

bool 型への変換には ParseBool 関数を使用します。

float 型への変換には ParseFloat 関数を使用します。
1つ目の引数には変換したい文字列を指定し、2つ目の引数には変換後の bit 数を指定します(bit 数に関わらず取得されるデータ型は float64 になります)。

int 型への変換には ParseInt 関数を使用します。
1つ目の引数には変換したい文字列を指定し、2つ目の引数には変換文字列の進数を指定し、3つ目の引数には変換後の bit 数を指定します(bit 数に関わらず取得されるデータ型は int64 になります)。

uint 型への変換には ParseUint 関数を使用します。
1つ目の引数には変換したい文字列を指定し、2つ目の引数には変換文字列の進数を指定し、3つ目の引数には変換後の bit 数を指定します(bit 数に関わらず取得されるデータ型は uint64 になります)。

(2進数や 16 進数に変換する場合)
2進数や 16 進数に変換する場合は、次のようになります。

main.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    i, err := strconv.ParseInt("ffff", 16, 64)
    fmt.Printf("%T, %d\n", i, i) // int64, 65535
    fmt.Println(err)             // <nil>

    u, err := strconv.ParseUint("11111111", 2, 64)
    fmt.Printf("%T, %d\n", u, u) //uint64, 255
    fmt.Println(err)             // <nil>

    u2, err := strconv.ParseUint("42", 2, 64)
    fmt.Printf("%T, %d\n", u2, u2) // uint64, 0
    fmt.Println(err)  // strconv.ParseUint: parsing "42": invalid syntax
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
int64, 65535
<nil>
uint64, 255
<nil>
uint64, 0
strconv.ParseUint: parsing "42": invalid syntax

最後の例は、"42" という数字を2進数に変換しようとしたが、01 以外の数字が含まれているため、エラーが発生した場合です。

3-2. 数値から文字列への変換

3-2-1. 一般的な変換

数値から文字列への変換は、Itoa 関数を使用します(itoa とは「Integer to ASCII」の意です)。
コードを書くと、次のようになります。

main.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    var num int = 100
    var str string = strconv.Itoa(num)
    fmt.Println(str)  // 100
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
100

出力値の見た目は 100 ですが、文字列に変換されています。

3-2-2. 詳細な変換指定

main.go
package main

import (
    "fmt"
    "strconv"
)

func main() {
    s1 := strconv.FormatBool(true)
    fmt.Printf("%T, %s\n", s1, s1) // string, true

    s2 := strconv.FormatFloat(3.1415, 'E', -1, 64)
    fmt.Printf("%T, %s\n", s2, s2) // string, 3.1415E+00

    s3 := strconv.FormatInt(-42, 16)
    fmt.Printf("%T, %s\n", s3, s3) // string, -2a

    s4 := strconv.FormatUint(42, 16)
    fmt.Printf("%T, %s\n", s4, s4) // string, 2a
}
ターミナル(コマンドプロンプト)
C:\golang\sample>go build main.go
C:\golang\sample>.\main
string, true
string, 3.1415E+00
string, -2a
string, 2a

bool 型から string 型への変換には FormatBool 関数を使用します。

float 型から string 型への変換には FormatFloat 関数を使用します。
1つ目の引数には変換したい実数を指定し、2つ目の引数には浮動小数点数の書式を表す指定子を指定し、3つ目の引数には変換後小数点の桁数を指定し(-1 は全て表示)、4つ目の引数には変換後の浮動小数点数の精度(bit 数)を指定します。

int 型から string 型への変換には FormatInt 関数を使用します。
1つ目の引数には変換したい整数を指定し、2つ目の引数には変換する数値の進数を指定します。

uint 型から string 型への変換には FormatUint 関数を使用します。
1つ目の引数には変換したい整数を指定し、2つ目の引数には変換する数値の進数を指定します。

詳しくは、下記のサイトが分りやすいです。

<参考>
【Go入門】strconvパッケージ ~ 文字列型と数値型・論理型の相互変換

さいごに

Go を触り始めたばかりなので間違いもあるかと思います。
お気づきのことなどありましたら、ご指摘いただけると幸いです。

11
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
12