
strconv.FormatInt 转换进制的正确用法
strconv.FormatInt 不是万能进制转换函数,它只支持 2–36 进制,且输入必须是 int64。如果你传入 int(比如 int 在 32 位系统上是 32 位),直接强转可能截断;传入负数时,结果会带负号前缀(如 -1010),这不是“补码表示”,只是字符串拼接负号。
实操建议:
- 始终显式转成
int64:用int64(x),别依赖隐式提升 - 进制基数必须是
2到36的整数,传1、0或37会 panic - 想转十六进制小写用
16,大写需后续调用strings.ToUpper - 二进制输出不含前缀(如无
0b),八进制也不含0o,十六进制不含0x
示例:
fmt.Println(strconv.FormatInt(int64(255), 2)) // "11111111"<br>fmt.Println(strconv.FormatInt(int64(-8), 2)) // "-1000"
为什么不能用 FormatInt 处理 uint64 或自定义进制逻辑
strconv.FormatInt 只接受 int64,不接受 uint64。强行转成 int64 会导致大于 math.MaxInt64(即 9223372036854775807)的值溢出变负,结果完全错误。
立即学习“go语言免费学习笔记(深入)”;
常见错误现象:
- 对
uint64(1 调用 <code>FormatInt(int64(x), 16)→ 输出负数的十六进制字符串 - 想实现 62 进制(0-9a-zA-Z)或 Base64 编码 →
FormatInt根本不支持,会 panic - 需要带前缀(如
0x、0b)→ 得自己拼接,它不提供格式化开关
替代方案:对 uint64,用 strconv.FormatUint;对非常规进制,手写循环取余 + 查表,别硬套 FormatInt。
性能和兼容性要注意的边界点
在高频场景(如日志 ID 生成、序列化中间层)里,strconv.FormatInt 是安全且足够快的,但有几点容易被忽略:
- 它分配新字符串,不复用缓冲区 —— 如果你反复转换同一组小整数,考虑预建 map 做查表(如
map[int64]string) - Go 1.0 就存在,无兼容性问题;但 Go 1.20+ 对
fmt.Sprintf("%b", x)做了优化,某些场景下比FormatInt(x, 2)略快(差异在纳秒级,一般不用切) - 并发安全:函数纯无状态,可放心多 goroutine 同时调用
注意:FormatInt(0, 16) 返回 "0",不是空字符串;FormatInt(0, 2) 也是 "0",这点和某些手写算法不同,别假设它会返回空。
实际项目中怎么选:FormatInt vs fmt.Sprintf vs 自定义
大多数情况直接用 strconv.FormatInt,干净、明确、无副作用。只有三种情况该换:
- 要转
uint64→ 改用strconv.FormatUint - 要带前缀或固定宽度(如
"0x00ff")→ 用fmt.Sprintf,例如fmt.Sprintf("0x%04x", x) - 进制超出 36,或字符集非标准(如去掉字母
o防混淆)→ 必须手写,用for x > 0 { digits = append(digits, table[x%base]); x /= base }
一个典型误用:有人为图省事把 int 直接丢给 FormatInt,在 32 位环境或大数值时静默出错。最稳妥的写法永远是 strconv.FormatInt(int64(myInt), 16),多敲四个字符,少 debug 两小时。










