Golang中如何比较数组类型结构体以判断数据是否变更?
Golang中Exchange结构体数组比较失败的解决方法
问题背景
需要比较两个[]Exchange数组(一个来自网页爬取,一个从数据库读取)以判断数据是否变更,但直接相等判断和reflect.DeepEqual均返回不相等。
结构体定义
type Exchange struct { Name string `gorm:"Column:name" json:"name"` Buy float64 `gorm:"Column:buy" json:"buy"` Sell float64 `gorm:"Column:sell" json:"sell"` }
数据示例
- 爬取结果输出:
&[{Dólar 38.5 41 } {Euro 38.82 43.57 } {P. Argentino 0.05 0.35 } {Real 6.95 8.95 }]
- 数据库结果输出:
&[{Dólar 38.5 41} {Euro 38.82 43.57} {P. Argentino 0.05 0.35} {Real 6.95 8.95}]
测试代码
fmt.Println(exchanges) dbExchanges := getExchangesFromDB() fmt.Println(dbExchanges) if exchanges == dbExchanges { fmt.Println("is equal") } else { fmt.Println("no is equal") } fmt.Println("Struct equal: ", reflect.DeepEqual(exchanges, dbExchanges))
问题原因
- float64精度问题:浮点数在存储和解析过程中可能出现微小精度差异(比如爬取解析时的
38.5可能实际是38.5000000001,数据库读取的是38.5),reflect.DeepEqual会严格判断浮点数的二进制表示是否完全一致,导致误判。 - 数组元素顺序不一致:如果爬取的数组和数据库返回的数组元素顺序不同,即使内容一致,整体数组也会被判定为不相等。
- 输出格式误导:示例中爬取结果的
Sell字段显示有空格,这只是fmt.Println的输出格式问题,实际字段是float64类型,不会包含空格,但仍可能存在精度差异。
解决方案
1. 为Exchange结构体实现自定义相等方法
针对float64的特性,使用精度阈值(epsilon)判断浮点数是否足够接近:
import "math" const epsilon = 1e-9 func (e Exchange) Equal(other Exchange) bool { if e.Name != other.Name { return false } // 判断Buy是否足够接近 if math.Abs(e.Buy - other.Buy) > epsilon { return false } // 判断Sell是否足够接近 return math.Abs(e.Sell - other.Sell) <= epsilon }
2. 实现数组比较函数
遍历两个数组的元素,逐一调用自定义的Equal方法,同时处理顺序不一致的情况(可选):
import "sort" func ExchangesEqual(a, b []Exchange) bool { if len(a) != len(b) { return false } // 如果顺序可能不一致,先按Name排序再比较 sort.Slice(a, func(i, j int) bool { return a[i].Name < a[j].Name }) sort.Slice(b, func(i, j int) bool { return b[i].Name < b[j].Name }) for i := range a { if !a[i].Equal(b[i]) { return false } } return true }
3. 使用自定义函数替代默认比较
修改测试代码,使用自定义的比较函数:
fmt.Println(exchanges) dbExchanges := getExchangesFromDB() fmt.Println(dbExchanges) if ExchangesEqual(exchanges, dbExchanges) { fmt.Println("数据无变更") } else { fmt.Println("数据已变更") }
注意事项
- 调整epsilon值:根据业务需求调整精度阈值,比如如果汇率保留两位小数,epsilon可以设为
1e-2(0.01)。 - 处理排序场景:如果爬取和数据库的元素顺序固定,可省略排序步骤以提升性能;若顺序不确定,必须排序后再比较。
内容的提问来源于stack exchange,提问作者user3058963
相关产品推荐
相关产品推荐

