You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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))

问题原因

  1. float64精度问题:浮点数在存储和解析过程中可能出现微小精度差异(比如爬取解析时的38.5可能实际是38.5000000001,数据库读取的是38.5),reflect.DeepEqual会严格判断浮点数的二进制表示是否完全一致,导致误判。
  2. 数组元素顺序不一致:如果爬取的数组和数据库返回的数组元素顺序不同,即使内容一致,整体数组也会被判定为不相等。
  3. 输出格式误导:示例中爬取结果的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:30:48