
go标准库支持直接通过fmt.sprintf("%x")或fmt.printf("%x")将big.int和big.rat格式化为小写或大写十六进制字符串,无需手动处理符号位或补码,适用于正负整数及有理数。
go标准库支持直接通过fmt.sprintf("%x")或fmt.printf("%x")将big.int和big.rat格式化为小写或大写十六进制字符串,无需手动处理符号位或补码,适用于正负整数及有理数。
在 Go 中,math/big 包提供的 *big.Int 和 *big.Rat 类型原生实现了 fmt.Formatter 接口,因此可直接使用 fmt 包的动词(如 %x、%X)进行十六进制格式化输出——无需自行实现补码转换、符号扩展或分母/分子拆解逻辑。
✅ 正确用法如下:
-
%x:输出小写十六进制(如3b、fffd5) -
%X:输出大写十六进制(如3B、FFFD5) - 对负数
*big.Int(如-59),Go 默认以 二进制补码形式的绝对值表示 + 前导负号(即-3b),而非无符号扩展的0xff...形式;这符合人类可读性优先的设计原则,也避免了位宽歧义(因*big.Int是任意精度,无固定字长)。 - 对
*big.Rat(有理数),%x会将其约分后的分子以十六进制输出,并附加/和分母的十六进制(例如3/4→3/4,而15/16→f/10)。
以下为完整示例代码:
package main
import (
"fmt"
"math/big"
)
func main() {
// big.Int 示例
negInt := big.NewInt(-59)
posInt := big.NewInt(59)
fmt.Printf("负整数(小写): %x\n", negInt) // 输出: -3b
fmt.Printf("负整数(大写): %X\n", negInt) // 输出: -3B
fmt.Printf("正整数(小写): %x\n", posInt) // 输出: 3b
// big.Rat 示例:3/4, 15/16, -7/8
r1 := big.NewRat(3, 4)
r2 := big.NewRat(15, 16)
r3 := big.NewRat(-7, 8)
fmt.Printf("有理数 3/4: %x\n", r1) // 输出: 3/4
fmt.Printf("有理数 15/16: %x\n", r2) // 输出: f/10
fmt.Printf("有理数 -7/8: %x\n", r3) // 输出: -7/8
// 若需纯无符号十六进制(如用于哈希或序列化),且确定数值非负,
// 可先调用 .Abs() 获取绝对值再格式化:
absNeg := new(big.Int).Abs(negInt)
fmt.Printf("|-59| 十六进制: %x\n", absNeg) // 输出: 3b
}⚠️ 注意事项:
立即学习“go语言免费学习笔记(深入)”;
-
*big.Int的负数不会自动转为补码十六进制(如0xffffffffffffffc5),因为其位宽不固定;若业务强依赖固定长度补码表示(如 256 位 EVM 地址),需配合Bytes()方法 + 手动填充/截断 +hex.EncodeToString()实现; -
*big.Rat.String()默认输出十进制分数,而%x是唯一内置的十六进制分数表示方式; - 所有格式化均基于约分后最简形式,无需额外调用
.SetFrac()或.FloatString()。
总结:对绝大多数场景(日志、调试、协议元数据),直接使用 fmt.Sprintf("%x", x) 是最简洁、安全、符合 Go 惯例的方案。


















