Goは型を暗黙に変換しません。互換性のある型どうしは T(v) で、数値とテキストの間は strconv パッケージで変換します。最もよく検索される2つの変換は次のとおりです。
strconv.Itoa(「integer to ASCII」)は int を10進のテキストに整形します。strconv.Atoi(「ASCII to integer」)はテキストを int に解析し、テキストが有効な数値でなければエラーを返します。そのエラーは必ずチェックしてください。
T(v)による変換
Goの変換の構文は、変換先の型の名前を使った関数呼び出しのように見えます。使えるのは次の3つの場面です。
- 数値型どうし(
int、int64、float64、uint8など) stringと[]byteまたは[]runeの間- 基底型が同じ型どうし(
Celsiusとfloat64)
結果をよく見てください。
int(3.9)は3、int(-3.9)は-3です。変換は ゼロ方向に切り捨て ます。四捨五入はしません。挙動を選ぶには、先にmath.Round、math.Floor、math.Ceilを使います。math.Roundは0.5をゼロから遠い方向に丸めるので、-3.5は-4になります。uint8(300)は44です。下位8ビットだけが残るからです(300から256を引いた値)。int8(200)が-56になるのも同じ理由です。エラーもpanicもありません。Celsiusとfloat64は基底型が同じなので自由に変換できますが、明示的に書く必要があります。
値をわざと変数に入れているのには理由があります。定数だと、同じ変換がコンパイルできません。
定数はチェックされ、変数はされない
収まらない定数を変換するとコンパイルエラーになります。同じ値の変数を変換すると、何も言わずに折り返します。
fmt.Println(uint8(300)) // compile error
x := 300
fmt.Println(uint8(x)) // 44
./main.go:6:20: constant 300 overflows uint8
整数でない定数を整数型に変換するのも拒否されますが、同じ値の変数なら切り捨てられます。
./main.go:7:18: cannot convert -3.9 (untyped float constant) to type int
浮動小数点数の値が変換先の整数型の範囲外にある場合(たとえば int64(1e20))、結果は実装依存です。たとえばamd64とarm64では異なる答えになります。信頼できない値は、変換する前に範囲をチェックしてください。
数値を文字列に変換する
| 変換元 | 関数 | 例 | 結果 |
|---|---|---|---|
int | strconv.Itoa(n) | strconv.Itoa(-7) | "-7" |
int64 | strconv.FormatInt(n, base) | strconv.FormatInt(255, 16) | "ff" |
uint64 | strconv.FormatUint(n, base) | strconv.FormatUint(5, 2) | "101" |
float64 | strconv.FormatFloat(f, fmt, prec, 64) | strconv.FormatFloat(3.14159, 'f', 2, 64) | "3.14" |
bool | strconv.FormatBool(b) | strconv.FormatBool(true) | "true" |
| 何でも | fmt.Sprint(v) | fmt.Sprint(3.5) | "3.5" |
| 何でも(書式付き) | fmt.Sprintf(format, v) | fmt.Sprintf("%05d", 42) | "00042" |
FormatFloat は、書式を表すバイト(固定小数点の 'f'、指数表記の 'e'、短いほうを選ぶ 'g')、精度(-1 は「正確に往復できる最小の桁数」)、元の浮動小数点数のビットサイズ(64または32)を受け取ります。
strconv は fmt.Sprint より高速です。fmt.Sprint は値をインターフェースに包み、fmtの汎用的な整形処理を通るからです。ホットなループではこの差が表れますが、たまに変換する程度なら読みやすいほうを選べば十分です。
文字列を数値に変換する
| 変換先 | 関数 | 戻り値 |
|---|---|---|
int | strconv.Atoi(s) | int, error |
| 任意の符号付き整数 | strconv.ParseInt(s, base, bitSize) | int64, error |
| 任意の符号なし整数 | strconv.ParseUint(s, base, bitSize) | uint64, error |
| 浮動小数点数 | strconv.ParseFloat(s, bitSize) | float64, error |
| 真偽値 | strconv.ParseBool(s) | bool, error |
ParseInt は常に int64 を返します。bitSize 引数(0、8、16、32、64)は受け付ける範囲を決めるので、小さい型に変換しても結果が収まることが保証されます。base が0だと「接頭辞から推測する」という意味になり、0x1f、0o17、0b101、1_000 がどれも解析できます。
出力からわかることは次のとおりです。
" 42"は失敗します。Atoiが受け付けるのは省略可能な符号と数字だけです。bufioからの入力はたいてい\nで終わるので、取り除いてください。"4.2"はAtoiでは無効です。小数にはParseFloatを使います。- 範囲外のエラーのとき、
ParseIntは収まる最大の値(int8なら127)をエラーと一緒に返します。エラーがnilでないときは値を使わないでください。 - エラーは
strconv.ErrSyntaxかstrconv.ErrRangeをラップした*strconv.NumErrorの値なので、errors.Isで区別できます。
ParseBool は 1、t、T、TRUE、true、True と、それに対応するfalseの形を受け付けます。"yes" や "on" はエラーです。
string(65)の罠
整数を string に変換しても数字にはなりません。そのUnicodeコードポイントを持つ文字になります。
n := 65
s := string(n) // "A", not "65"
コンパイラは受け付けますが、go vet が報告します。
./main.go:10:7: conversion from int to string yields a string of one rune, not a string of digits
本当に文字がほしいなら、ルーンを使ってそう書きます:string(rune(n))。数値をテキストにしたいなら strconv.Itoa(n) を使います。rune や byte を string に変換するのは問題なく、よく使われます。
文字列、バイト、ルーン
string、[]byte、[]rune は T(v) で相互に変換できます。文字列は変更できず、スライスは変更できるので、どの変換もデータをコピーします。
文字単位でインデックスを使ったり変更したりするときは []rune に、I/O、ハッシュ計算、バイト単位の編集には []byte に変換します。UTF-8の詳細はルーンとバイトのページで扱っています。
変換と型アサーションの違い
変換は、ある具体的な型の値を別の具体的な型に変えるものです。インターフェース(any、error、io.Reader)から具体的な値を取り出すのは、型アサーションという別の操作です。
var v any = 42
n := v.(int) // type assertion: v holds an int, give it to me
f := float64(n) // conversion: int to float64
// f := float64(v) // compile error: cannot convert v (variable of interface type any)
// // to type float64: need type assertion
先にアサーションし、それから変換します。カンマok形式の n, ok := v.(int) を使えば、型が違ったときのpanicを避けられます。
早見表
| やりたいこと | コード |
|---|---|
| intを文字列に | strconv.Itoa(n) |
| int64を文字列に | strconv.FormatInt(n, 10) |
| 文字列をintに | n, err := strconv.Atoi(s) |
| 文字列をint64に | n, err := strconv.ParseInt(s, 10, 64) |
| 文字列をfloat64に | f, err := strconv.ParseFloat(s, 64) |
| float64を文字列に | strconv.FormatFloat(f, 'f', -1, 64) |
| float64をintに | int(f)(切り捨て)または int(math.Round(f)) |
| intをfloat64に | float64(n) |
| 文字列を[]byteに | []byte(s) |
| []byteを文字列に | string(b) |
| runeを文字列に | string(r) |
| boolを文字列に | strconv.FormatBool(b) |
| 任意の値を文字列に | fmt.Sprint(v) |
よくある質問
Goでintを文字列に変換するには?
strconv.Itoa(n) を使います:strconv.Itoa(42) は "42" を返します。int64 なら strconv.FormatInt(n, 10) を使います。fmt.Sprint(n) もどんな型にも使えますが、遅くなります。string(n) と書いてはいけません。n がUnicodeのコードポイントとして扱われ、string(65) は "A" になります。
Goで文字列をintに変換するには?
数値とエラーを返す strconv.Atoi を使います。
n, err := strconv.Atoi("42")
if err != nil {
// not a valid integer
}
サイズや基数を指定するなら、int64 を返す strconv.ParseInt(s, 10, 64) を使います。Atoiは空白を取り除かないので " 42" はエラーになります。先に strings.TrimSpace を呼んでください。
Goでキャストするには?
Goでは変換(conversion)と呼び、構文は T(v) です:float64(n)、int(f)、[]byte(s)。数値型どうし、文字列とbyteやruneのスライスの間、そして基底型が同じ型どうしで使えます。テキストの解析はしないので、"42" を 42 にするには strconv が必要です。インターフェースから具体的な型を取り出すのは変換ではなく型アサーション v.(T) です。
Goでfloatをintに変換するには?
int(f) はゼロ方向に切り捨てます:int(3.9) は 3、int(-3.9) は -3 です。四捨五入するなら int(math.Round(f)) を使います。浮動小数点数が整数型の範囲外だと結果は実装依存になるので、値が入力から来る場合は先に範囲をチェックします。
なぜGoのstring(65)は"A"を返すのですか?
整数を string に変換すると、Unicodeのコードポイントとして解釈されます。65は A のコードポイントです。go vet はこれを conversion from int to string yields a string of one rune, not a string of digits として報告します。"65" がほしいなら strconv.Itoa(65) を使います。