应使用github.com/paulmach/go.geo的distance函数,它封装haversine公式自动处理弧度转换与地球半径,输入度数返回米制距离,精度够用且无依赖。

Go里计算两点经纬度距离该用哪个库函数
直接用 github.com/paulmach/go.geo 的 Distance 函数最省事,它封装了球面余弦定理(Haversine),精度够用、无依赖、单文件可嵌入。别自己手写公式——容易漏掉弧度转换或地球半径单位混淆。
常见错误是把度数当弧度传给 math.Sin/math.Cos,结果距离偏差超 10%。这个库内部自动做 deg * math.Pi / 180 转换,你只管传 float64 度数。
-
Distance(lat1, lng1, lat2, lng2 float64) float64返回单位是米 - 如果需要千米,除以 1000;需要英里,除以 1609.344
- 输入纬度范围必须是 -90 ~ +90,经度 -180 ~ +180,越界会返回 NaN
如何避免高并发下 Haversine 计算成为性能瓶颈
纯 CPU 计算本身很快(纳秒级),瓶颈往往出在反复创建临时变量或频繁调用 math 函数。实测 100 万次调用 Distance 在普通服务器上约耗时 80ms,但若每次还顺带做 JSON 解析或 DB 查询,就掩盖了真实热点。
真正要优化的不是公式本身,而是调用上下文:
- 提前把经纬度转成弧度缓存,避免重复调用
toRadians - 批量计算时用 slice 预分配,别用
append动态扩容 - 如果只是判断“是否在 5km 内”,用平方距离近似(跳过开方和三角函数),误差
示例近似判断:
dx := (lng1 - lng2) * math.Cos((lat1+lat2)/2*toRad) dy := lat1 - lat2 approxDistM := math.Sqrt(dx*dx+dy*dy) * 111319.9 // 约 1° ≈ 111.3199 km
为什么用 Haversine 而不是 Euclidean 或 Vincenty
Euclidean(平面直角坐标系)只适合同一投影坐标系下的短距离(
Haversine 是平衡点:误差
- 误差来源主要是地球非完美球体,但对 POI 检索、附近人、配送范围等场景完全可接受
- 如果业务真要求亚米级(如测绘),再考虑
github.com/xyproto/geom的 Vincenty 实现 - 注意:所有库都假设 WGS84 坐标系,GPS 设备和主流地图 API(高德、Google Maps)默认输出就是 WGS84
测试时怎么验证距离计算没跑偏
别只写 “两个点算出来是 X 米” 这种静态断言。真实世界有典型锚点,比如:
- 赤道上经度差 1° ≈ 111319.9 米(固定值,可作基准)
- 同一经线上纬度差 1° ≈ 110574 米(极地略小,但误差
- 用已知结果的在线工具交叉验证,例如 movable-type.co.uk 输入相同坐标
特别注意中国地区常见坑:高德/腾讯地图返回的是 GCJ-02 坐标(加偏),直接喂给 Haversine 会导致 100–700m 偏差。必须先用 github.com/twpayne/go-gcjin 转回 WGS84 再算距离。
这事关定位准确性,但很容易被忽略——模块跑单元测试全绿,上线后发现“附近 5km 商家”漏掉一半。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











