Go语言中不同进制的互转方法:二进制/八进制/十六进制互转方法
作为 Go 开发者,日常开发中难免会遇到进制转换的需求 —— 比如处理网络协议中的二进制数据、配置文件中的十六进制参数、日志中的八进制权限值等。
Go 标准库中的strconv包提供了完善的进制转换工具,无需手动实现复杂算法,就能轻松完成二进制、八进制、十六进制与十进制的互转。
本文结合实际开发场景,详细拆解各类进制转换的实现逻辑、代码示例及避坑指南,让你彻底掌握 Go 语言的进制操作
一、二进制与十进制互转(常用)
二进制以0b为前缀,十进制是默认进制,两者互转是基础中的基础。
(一)二进制字符串 → 十进制整数
使用strconv.ParseInt(),指定base=2(表示输入字符串是二进制),bitSize根据需求选择(8/16/32/64,对应 int8/int16/int32/int64)。
package main
import (
"fmt"
"strconv"
)
func main() {
// 二进制字符串(可带0b前缀,也可不带)
binStr1 := "1010" // 不带前缀,等价于10
binStr2 := "0b1101" // 带0b前缀,等价于13
// 转换:base=2表示二进制,bitSize=64表示转成int64
dec1, err := strconv.ParseInt(binStr1, 2, 64)
if err != nil {
fmt.Printf("二进制转十进制失败:%v\n", err)
} else {
fmt.Printf("二进制%s → 十进制:%d\n", binStr1, dec1) // 输出:1010 → 10
}
// 带前缀的二进制字符串转换(注意:base=2时,前缀0b会被自动忽略,无需手动处理)
dec2, err := strconv.ParseInt(binStr2, 2, 64)
if err != nil {
fmt.Printf("二进制转十进制失败:%v\n", err)
} else {
fmt.Printf("二进制%s → 十进制:%d\n", binStr2, dec2) // 输出:0b1101 → 13
}
}(二)十进制整数 → 二进制字符串
使用strconv.FormatInt(),指定base=2,返回的字符串默认不带0b前缀(如需前缀可手动拼接)。
func main() {
dec := 25 // 十进制25
// 十进制转二进制(不带前缀)
binStr := strconv.FormatInt(int64(dec), 2)
fmt.Printf("十进制%d → 二进制(无前缀):%s\n", dec, binStr) // 输出:11001
// 十进制转二进制(带0b前缀)
binStrWithPrefix := "0b" + strconv.FormatInt(int64(dec), 2)
fmt.Printf("十进制%d → 二进制(带前缀):%s\n", dec, binStrWithPrefix) // 输出:0b11001
}二、十进制与八进制互转
权限配置常用
八进制以0为前缀(Go 中八进制字面量必须带0),常用于表示文件权限(如0755)。
(一)八进制字符串 → 十进制整数
使用strconv.ParseInt(),指定base=8,注意输入字符串可带0前缀或不带。
func main() {
octStr1 := "12" // 不带前缀,等价于十进制10
octStr2 := "0755" // 带0前缀,文件权限常用,等价于十进制493
// 不带前缀转换
dec1, err := strconv.ParseInt(octStr1, 8, 64)
if err != nil {
fmt.Printf("八进制转十进制失败:%v\n", err)
} else {
fmt.Printf("八进制%s → 十进制:%d\n", octStr1, dec1) // 输出:12 → 10
}
// 带前缀转换(base=8时,前缀0会被自动忽略)
dec2, err := strconv.ParseInt(octStr2, 8, 64)
if err != nil {
fmt.Printf("八进制转十进制失败:%v\n", err)
} else {
fmt.Printf("八进制%s → 十进制:%d\n", octStr2, dec2) // 输出:0755 → 493
}
}(二)十进制整数 → 八进制字符串
使用strconv.FormatInt(),指定base=8,返回字符串默认不带0前缀(如需前缀手动拼接)。
func main() {
dec := 493 // 十进制493,对应文件权限0755
// 不带前缀
octStr := strconv.FormatInt(int64(dec), 8)
fmt.Printf("十进制%d → 八进制(无前缀):%s\n", dec, octStr) // 输出:755
// 带0前缀(文件权限场景常用)
octStrWithPrefix := "0" + strconv.FormatInt(int64(dec), 8)
fmt.Printf("十进制%d → 八进制(带前缀):%s\n", dec, octStrWithPrefix) // 输出:0755
}三、十六进制与十进制互转
数据传输常用
十六进制以0x为前缀,常用于表示字节数据(如0xFF)、哈希值(如 MD5 结果)等场景。
(一)十六进制字符串 → 十进制整数
使用strconv.ParseInt(),指定base=16,输入字符串可带0x前缀或不带,支持大小写字母(A-F/a-f)。
func main() {
hexStr1 := "1A" // 不带前缀,等价于十进制26
hexStr2 := "0xFF" // 带0x前缀,等价于十进制255
hexStr3 := "0xa3" // 小写字母,等价于十进制163
dec1, err := strconv.ParseInt(hexStr1, 16, 64)
if err != nil {
fmt.Printf("十六进制转十进制失败:%v\n", err)
} else {
fmt.Printf("十六进制%s → 十进制:%d\n", hexStr1, dec1) // 输出:1A → 26
}
dec2, err := strconv.ParseInt(hexStr2, 16, 64)
if err != nil {
fmt.Printf("十六进制转十进制失败:%v\n", err)
} else {
fmt.Printf("十六进制%s → 十进制:%d\n", hexStr2, dec2) // 输出:0xFF → 255
}
dec3, err := strconv.ParseInt(hexStr3, 16, 64)
if err != nil {
fmt.Printf("十六进制转十进制失败:%v\n", err)
} else {
fmt.Printf("十六进制%s → 十进制:%d\n", hexStr3, dec3) // 输出:0xa3 → 163
}
}(二)十进制整数 → 十六进制字符串
使用strconv.FormatInt(),指定base=16,返回字符串默认小写(如需大写可使用strings.ToUpper()),不带0x前缀。
import "strings"
func main() {
dec := 255 // 十进制255
// 小写不带前缀
hexStrLower := strconv.FormatInt(int64(dec), 16)
fmt.Printf("十进制%d → 十六进制(小写):%s\n", dec, hexStrLower) // 输出:ff
// 大写带0x前缀(哈希值场景常用)
hexStrUpper := "0x" + strings.ToUpper(strconv.FormatInt(int64(dec), 16))
fmt.Printf("十进制%d → 十六进制(大写带前缀):%s\n", dec, hexStrUpper) // 输出:0xFF
}四、跨进制直接互转
无需经过十进制
上述方法都是以十进制为桥梁,但部分场景下可直接实现二进制、八进制、十六进制的互转
本质是 “目标进制→十进制→目标进制” 的简化写法,代码更简洁。
(一)二进制 → 十六进制
func main() {
binStr := "11010110" // 二进制字符串
// 步骤1:二进制转十进制
dec, err := strconv.ParseInt(binStr, 2, 64)
if err != nil {
fmt.Printf("转换失败:%v\n", err)
return
}
// 步骤2:十进制转十六进制(大写带前缀)
hexStr := "0x" + strings.ToUpper(strconv.FormatInt(dec, 16))
fmt.Printf("二进制%s → 十六进制:%s\n", binStr, hexStr) // 输出:11010110 → 0xD6
}(二)十六进制 → 八进制
func main() {
hexStr := "0x1A3" // 十六进制字符串
// 步骤1:十六进制转十进制
dec, err := strconv.ParseInt(hexStr, 16, 64)
if err != nil {
fmt.Printf("转换失败:%v\n", err)
return
}
// 步骤2:十进制转八进制(带前缀)
octStr := "0" + strconv.FormatInt(dec, 8)
fmt.Printf("十六进制%s → 八进制:%s\n", hexStr, octStr) // 输出:0x1A3 → 0643
}常见问题
Q1、字符串前缀导致转换失败?
输入字符串带前缀(如0b/0/0x)时,忘记处理导致strconv.ParseInt()报错。
解:strconv.ParseInt()的base参数指定后,会自动忽略对应前缀(如base=2忽略0b,base=8忽略0,base=16忽略0x),无需手动截取前缀。
Q2、整数溢出导致转换异常?
转换后的整数超出bitSize指定的范围(如将一个 32 位二进制数转成bitSize=16的整数)
解:根据实际需求选择bitSize(如不确定,直接用64,对应int64,兼容性最强);转换前可先估算目标进制的数值范围。
// 错误:二进制10000000000000000000000000000000(32位)转成bitSize=16
binStr := "10000000000000000000000000000000"
dec, err := strconv.ParseInt(binStr, 2, 16)
fmt.Println(err) // 输出:strconv.ParseInt: parsing "10000000000000000000000000000000": value out of rangeQ3、字符大小写导致十六进制转换失败?
十六进制字符串包含大写字母(如0XFF),担心转换失败
解:strconv.ParseInt()支持大小写字母,无需额外处理;如果需要统一输出格式,可使用strings.ToUpper()或strings.ToLower()转换
Q4、十进制转其他进制后,需要固定位数?
转换后的字符串长度不足(如需要二进制固定 8 位、十六进制固定 2 位)。
解:使用fmt.Sprintf()格式化输出,指定宽度和填充字符(通常用0填充)。
func main() {
dec := 5 // 十进制5
// 二进制固定8位,不足补0
binStr := fmt.Sprintf("%08b", dec)
fmt.Println(binStr) // 输出:00000101
// 十六进制固定2位,不足补0
hexStr := fmt.Sprintf("%02X", dec)
fmt.Println(hexStr) // 输出:05
}Q5、strconv.Atoi()与strconv.ParseInt()的区别?
strconv.Atoi():简化版,仅支持十进制字符串转int,等价于strconv.ParseInt(s, 10, 0)(bitSize=0表示根据系统架构自动选择 32 位或 64 位)。strconv.ParseInt():通用版,支持任意进制(2-36 进制),可指定整数类型(bitSize),功能更强大。- 建议:除了简单的十进制转换,优先使用
strconv.ParseInt(),兼容性更强。
总结
go实现进制之间的转换也非常简单;通过标准库就可以实现进制转换:
- strconv包:处理字符串与数值互转
- fmt格式化:快速生成进制字符串
- 位运算:高效处理二进制位操作
如果遇到特殊场景(如自定义进制、大整数进制转换),可以留言讨论,后续会补充更进阶的实现方案!
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!
本文原文链接: https://fiveyoboy.com/articles/go-base-convert/
备用原文链接: https://blog.fiveyoboy.com/articles/go-base-convert/