Menu

Golang int 转 string、string 转 int 与类型转换

如何在 Go 中进行类型转换:用 strconv 实现 int 转 string 和 string 转 int,浮点数转整数,用 T(v) 做数值转换,字节与 rune,string(65) 的陷阱,以及处理转换错误。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

Go 从不进行隐式类型转换。兼容的类型之间用 T(v) 转换,数字和文本之间用 strconv 包转换。下面是被搜索最多的两种转换:

strconv.Itoa(“integer to ASCII”)把 int 格式化成十进制文本。strconv.Atoi(“ASCII to integer”)把文本解析成 int,文本不是有效数字时返回错误。一定要检查这个错误。

T(v) 转换

Go 的转换语法看起来像一次以目标类型命名的函数调用。它适用于三种情况:

  1. 数值类型之间(int、int64、float64、uint8 等),
  2. string 与 []byte 或 []rune 之间,
  3. 底层类型相同的类型之间(Celsius 和 float64)。

仔细看看结果:

  • int(3.9) 是 3,int(-3.9) 是 -3。转换会向零截断,而不是四舍五入。要选择其他行为,先用 math.Round、math.Floor 或 math.Ceil。math.Round 遇到 .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 会给出不同的答案。转换不可信的值之前,先检查范围。

数字转字符串

源类型函数示例结果
intstrconv.Itoa(n)strconv.Itoa(-7)"-7"
int64strconv.FormatInt(n, base)strconv.FormatInt(255, 16)"ff"
uint64strconv.FormatUint(n, base)strconv.FormatUint(5, 2)"101"
float64strconv.FormatFloat(f, fmt, prec, 64)strconv.FormatFloat(3.14159, 'f', 2, 64)"3.14"
boolstrconv.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 通用的格式化流程。在热点循环中这个差距会显现出来;偶尔转换一下的话,选读起来更顺的那个就行。

字符串转数字

目标类型函数返回
intstrconv.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

如果你确实想要那个字符,就用 rune 明确表达:string(rune(n))。如果你想要的是数字文本,用 strconv.Itoa(n)。把 rune 或 byte 转换成 string 没有问题,也很常见:

字符串、字节与 rune

string、[]byte 和 []rune 可以用 T(v) 互相转换。每次转换都会复制数据,因为字符串是不可变的,而切片不是:

需要按字符索引或修改时,转换成 []rune;做 I/O、哈希和字节级修改时,转换成 []byte。rune 和字节一节会详细讲解 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

先断言,再转换。comma-ok 形式 n, ok := v.(int) 可以避免类型不对时 panic。

速查表

任务代码
int 转 stringstrconv.Itoa(n)
int64 转 stringstrconv.FormatInt(n, 10)
string 转 intn, err := strconv.Atoi(s)
string 转 int64n, err := strconv.ParseInt(s, 10, 64)
string 转 float64f, err := strconv.ParseFloat(s, 64)
float64 转 stringstrconv.FormatFloat(f, 'f', -1, 64)
float64 转 intint(f)(截断)或 int(math.Round(f))
int 转 float64float64(n)
string 转 []byte[]byte(s)
[]byte 转 stringstring(b)
rune 转 stringstring(r)
bool 转 stringstrconv.FormatBool(b)
任意值转 stringfmt.Sprint(v)

常见问题

Go 中如何把 int 转成 string?

用 strconv.Itoa(n):strconv.Itoa(42) 返回 "42"。int64 用 strconv.FormatInt(n, 10)。fmt.Sprint(n) 也适用于任何类型,但更慢。不要写 string(n):它会把 n 当作 Unicode 码点,所以 string(65) 是 "A"。

Go 中如何把 string 转成 int?

用 strconv.Atoi,它返回数字和一个错误:

n, err := strconv.Atoi("42")
if err != nil {
	// not a valid integer
}

需要指定位数或进制时,用 strconv.ParseInt(s, 10, 64),它返回 int64。Atoi 不会去掉空格,所以 " 42" 会报错;请先调用 strings.TrimSpace。

Go 中如何强制类型转换?

Go 称之为转换,语法是 T(v):float64(n)、int(f)、[]byte(s)。它适用于数值类型之间、字符串与字节切片或 rune 切片之间,以及底层类型相同的类型之间。它不会解析文本:把 "42" 变成 42 需要用 strconv。从接口中取出具体类型是类型断言 v.(T),而不是转换。

Go 中如何把浮点数转成整数?

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

Coddy 编程语言插图

和 Coddy 一起学编程

开始