strconv.FormatFloat是最可控的浮点数格式化起点,但Go中无统一精度解,需按场景选语义:写入文件用'f'和-1去零,JSON序列化用json.Marshal,展示用fmt.Sprintf,计算直接用float64并接受IEEE-754误差。

strconv.FormatFloat 是最可控的起点,但“完整教程”这个词容易让人误以为存在银弹——实际上 Go 中浮点数精度控制没有统一解,只有场景适配:你要的是写入文件?JSON 序列化?展示日志?还是参与后续计算?选错路径,后面调半天也白搭。
用 strconv.FormatFloat 控制小数位数时,第三个参数决定行为
这个参数不是“保留几位”,而是“怎么解释精度”:
- 传正整数(如
2)→ 强制保留该位小数,末尾补零:strconv.FormatFloat(3.1, 'f', 2, 64)→"3.10" - 传
-1→ 不四舍五入,只输出最少必要位数:strconv.FormatFloat(5.0, 'f', -1, 64)→"5",strconv.FormatFloat(3.1400, 'f', -1, 64)→"3.14" - 传
-1不等于“最多 N 位”——它忠实地还原该float64值的最简十进制表示,3.1415926535就会原样吐出全部位数
需要“最多 N 位小数且去零”?得先数学缩放再格式化
strconv.FormatFloat 本身不支持“上限”逻辑。若你明确要 3.14159 → "3.14"(非 "3.14159"),必须预处理:
- 用
math.Round(x * math.Pow10(n)) / math.Pow10(n)四舍五入到 N 位(注意:这是近似,受 IEEE-754 限制) - 再用
strconv.FormatFloat(..., 'f', -1, 64)去掉尾随零 - 别用
fmt.Sprintf("%.2f", x)替代——它在x=0.001时输出"0.00",而你可能想要"0.001" -
bitSize必须是64(对应float64),传32会 panic
写入文件时,格式化只是前半程,I/O 才是翻车高发区
常见空文件或崩溃,往往和格式化无关:
-
os.Create或os.OpenFile后忽略err→ 文件句柄为nil,后续fmt.Fprintf直接 panic - 忘记
file.Close()→ 缓冲区未刷新,小文件内容可能完全没落盘;务必defer file.Close() - 并发写同一文件 → 没加锁会导致内容乱序或覆盖;要么串行,要么用
bufio.NewWriter包一层减少系统调用 - 拼 JSON 字段时手拼字符串:
"lat": " + strconv.FormatFloat(lat, 'f', -1, 64) + ","→ 引号、转义全靠猜;改用json.Marshal或fmt.Fprintf(w, `"lat":%s`, s)
真正难的不是“怎么写”,而是判断该用哪种语义
选错语义,后面所有优化都无效:
- 展示用(如日志、前端显示)→ 可接受
fmt.Sprintf("%.2f", x)的四舍五入,简单够用 - 存储用(如写配置、导出 CSV)→ 要求可逆,优先
strconv.FormatFloat(x, 'f', -1, 64),避免无谓补零 - 参与后续计算(如累加、比较)→ 别转字符串!直接用
float64运算,但需接受 IEEE-754 误差;金额、汇率等敏感场景,必须换github.com/shopspring/decimal
最后提醒一句:float64 本质是二进制近似,0.1 + 0.2 != 0.3 不是 bug,是设计。别试图“修”它,该绕开就绕开。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











