github.com/shopspring/decimal:NewFromString与NewFromFloat64生成值不一致导致gomock断言失败问题问询
为什么decimal.NewFromString和NewFromFloat64生成的实例在Gomock断言中不匹配?
这是个很典型的浮点数精度+库内部表示导致的问题,我来给你拆解清楚:
核心原因
浮点数的天生精度缺陷
float64类型在二进制存储时,无法精确表示所有十进制小数——哪怕是看起来像整数的数值,某些场景下也会存在近似存储的情况。decimal.NewFromFloat64是基于浮点数的近似二进制值转换生成decimal实例,而decimal.NewFromString是直接解析十进制字符串的精确数值,两者的内部存储(比如big.Int的系数、指数值)可能会出现细微差异。Gomock的默认匹配逻辑
Gomock默认用reflect.DeepEqual来比较参数是否相等。对于decimal类型来说,它的内部结构包含*big.Int指针,即使两个实例的数值看起来一样,只要指针指向的不是同一个big.Int对象,或者内部系数/指数有差异,reflect.DeepEqual就会判定它们不相等。而当你在测试和业务代码中都用NewFromString生成实例时,两者的精确内部表示完全一致,自然能通过断言。
解决办法
针对这个问题,你有几个实用的处理方式:
- 统一生成方式:测试中完全复刻业务代码的逻辑,用
decimal.NewFromString创建预期参数,从根源避免浮点数转换带来的精度问题。 - 自定义匹配器:如果必须用浮点数生成测试参数,可以借助Gomock的自定义匹配器,用decimal自身的
Equal方法来判断数值是否相等(而不是依赖默认的反射比较),示例代码如下:value := decimal.NewFromFloat64(1000) cfg.cdi.EXPECT().CreateBuyEvent(ctx, gomock.Matches(func(v decimal.Decimal) bool { return v.Equal(value) })).Return(nil) - 避免浮点数传入:在涉及精确数值的场景中,尽量用字符串或整数来初始化decimal,从源头规避浮点数精度风险。
内容的提问来源于stack exchange,提问作者stizzo96
相关产品推荐
相关产品推荐

