不能直接用 math.Hypot 计算经纬度距离,因地球是球面而该函数基于平面勾股定理,会导致巨大误差(如北京到上海误算为300km而非1200km);应使用球面三角模型,首选Haversine公式。

为什么别直接用 math.Hypot 算经纬度距离
地球是球面,经纬度是球面坐标,用平面勾股定理算两点距离误差极大——赤道上1度经度≈111km,到北极就趋近于0。直接套 math.Hypot 会把北京到上海算成不到300km(实际约1200km)。必须用球面三角模型,最常用的是 Haversine 公式,它在精度和性能间平衡得足够好,误差通常
封装成可复用模块的关键设计点
Go 没有默认的地理计算包,自己封装时要避开几个硬伤:
-
float64是必须的——经纬度输入/输出都该用float64,别用int或字符串,避免反复转换 - 单位统一:输入是十进制度数(如
39.9042),输出默认是米(float64),别混用 km/m/海里 - 边界检查不能省:纬度必须在
[-90, 90],经度建议限制在[-180, 180],否则 Haversine 公式结果无意义 - 导出函数名要直白:
Distance比CalcDist更符合 Go 习惯,参数顺序按惯例:纬度、经度(lat1, lng1, lat2, lng2)
一个最小可用的 distance.go 实现
不需要依赖第三方库,标准库全搞定。核心就是 Haversine 公式,注意弧度转换和地球半径取值:
package distance
<p>import (
"math"
)</p><p>const EarthRadius = 6371008.7714 // 米,WGS84 平均半径</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/gongju/2525" title="Go语言(Golang)1.26.0"><img
src="https://img.php.cn/upload/manual/001/589/237/6a6adeed24a4a355.png" alt="Go语言(Golang)1.26.0" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/gongju/2525" title="Go语言(Golang)1.26.0">Go语言(Golang)1.26.0</a>
<p>Go语言(Golang)1.26.0版本官方下载,版本号 1.26.0,适合旧项目维护、兼容性测试和指定版本开发环境搭建。</p>
</div>
<a href="/xiazai/gongju/2525" title="Go语言(Golang)1.26.0" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/00968c3c2c15" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">go语言免费学习笔记(深入)</a>”;</p><p>// Distance 返回两点间球面距离(单位:米)
// 输入:纬度、经度均为十进制度数
func Distance(lat1, lng1, lat2, lng2 float64) float64 {
// 边界检查(可选但强烈建议)
if lat1 < -90 || lat1 > 90 || lat2 < -90 || lat2 > 90 {
return 0
}</p><pre class="brush:php;toolbar:false;">// 转弧度
lat1Rad := lat1 * math.Pi / 180
lng1Rad := lng1 * math.Pi / 180
lat2Rad := lat2 * math.Pi / 180
lng2Rad := lng2 * math.Pi / 180
dLat := lat2Rad - lat1Rad
dLng := lng2Rad - lng1Rad
a := math.Sin(dLat/2)*math.Sin(dLat/2) +
math.Cos(lat1Rad)*math.Cos(lat2Rad)*
math.Sin(dLng/2)*math.Sin(dLng/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
return EarthRadius * c}
调用时容易被忽略的精度与性能陷阱
这个函数看似简单,但实际部署时有几个隐形坑:
- 如果批量计算(比如查附近1000个POI),别在循环里反复调用
Distance——提前把参考点转成弧度,复用math.Cos(lat1Rad)等中间值能提速约15% - 高纬度地区(如北欧)用 Haversine 仍有轻微偏差,要求亚米级精度时得换 Vincenty 公式(但计算慢3倍以上,且代码复杂得多)
- 别对
lng做简单差值判断“是否跨国际日期变更线”——经度差超过180°时需手动归一化,例如lng2 = (lng2 - lng1 + 540) % 360 - 180 - 测试用例必须覆盖极点(
lat=90)、本初子午线(lng=0)和反向经度(lng=179与lng=-179)
真正麻烦的不是写公式,而是让模块在各种边缘坐标下不 panic、不返回负数、不溢出——边界检查和测试比算法本身更耗时间。

















