Go语言中如何将float64类型NaN/Inf转换为*big.Rat类型
问题背景
当前使用goavro Avro工具库做序列化处理,项目所用Avro模式包含如下字段定义:
[{"name":"Col_1", "type":["null",{"type":"bytes", "logicalType":"decimal","precision":20,"scale":5}]}]
实际输入数据中存在NaN、Inf这类float64类型的特殊值。该decimal逻辑类型基于bytes类型实现,要求传入的数值必须为*big.Rat类型,但NaN、Inf属于float64特有的非有限值,无法直接转换为*big.Rat类型。
处理方案
首先明确核心前提:*big.Rat是有理数类型,本身设计上就无法表示非数值、无穷大这类特殊值,同时Avro官方的decimal逻辑类型规范也不支持NaN、Inf这类值,不存在原生的合法转换逻辑,需要结合业务场景选择对应处理方式:
- 走字段的null分支
该字段本身是["null", "decimal"]的联合类型,原生支持空值。如果业务允许NaN、Inf这类异常值按空处理,直接在转换前用标准库math包做判断,特殊值直接返回nil匹配null分支即可,参考实现:import ( "math" "math/big" ) func buildCol1Val(input float64) interface{} { // 识别NaN、正无穷、负无穷 if math.IsNaN(input) || math.IsInf(input, 0) { return nil } // 正常有限值转换为*big.Rat,可按需对齐scale=5的精度要求 return new(big.Rat).SetFloat64(input) } - 业务侧约定特殊值映射
如果业务需要保留NaN、Inf的语义,不能直接置空,需要和数据上下游提前约定不冲突的特殊编码值:比如当前字段precision=20、scale=5,正常业务取值不会触及上下限,就可以约定999999999999999.99999代表NaN、999999999999998.99999代表正无穷、-999999999999998.99999代表负无穷,转换时识别到特殊值直接返回对应约定值的*big.Rat实例即可。
注意:不要尝试通过修改
big.Rat内部私有字段的方式强行注入NaN/Inf语义,goavro序列化decimal时会做数值合法性校验,非法值会直接抛出错误,就算绕过本地校验,生成的数据也无法被其他Avro客户端正常解析。
内容的提问来源于stack exchange,提问作者A Beginner
相关产品推荐
相关产品推荐

