go-redis Do 调用 Text 报 float64 类型不符,检查 RESP3
同一ZSCORE在RESP2返回文本,RESP3却返回float64,Cmd.Text未必能转换。已知命令优先采用ZScore类型化接口,不靠强转整数丢掉小数。
用 rdb.Do(ctx, "ZSCORE", key, member).Text(),RESP2下能拿到分数字符串,RESP3下却报:
redis: unexpected type=float64 for String
这条错误不表示Redis把分数存坏了。RESP3可以直接返回双精度数,go-redis读取后得到 float64;受影响的通用 Cmd.Text() 却只接受字符串。
原生数值与文本回复不同
正式v9.23.0的 toString 只匹配 string,通用整数助手也只处理部分类型。Do() 的结果类型取决于实际协议和回复,不会因为调用了 .Text() 就先把服务器所有原生类型统一变成文本。
先检查这次命令是否成功、Result() 的实际Go类型,以及最终协议配置。不要仅为查看类型就把整份业务回复打印到日志。
如果命令本来就是已知的 ZSCORE,优先使用对应的类型化方法:
score, err := rdb.ZScore(ctx, key, member).Result()
score 是分数,调用方仍需按原逻辑处理 err,包括成员不存在时的 redis.Nil。不能忽略错误后把零值当成真实0分。
通用命令需要明确转换契约
必须保留 Do 的封装层,应基于成功的 Result() 做显式类型分支。文本协议返回的字符串按该字段约定解析;RESP3的 float64 按数值处理。最终确实需要展示字符串时,再选择与应用约定一致的格式。
不要直接把 float64 转成 int64。1.5这类合法分数会被截断,范围外和非有限值还需要独立规则。通用的整数接口不能为了兼容协议就悄悄接受所有小数。
RESP3大整数也有类似边界,但读取类型可能是 *big.Int,不是普通 int64。需要精确整数时保持大整数表示;先转浮点再转回整数,可能永久丢失精度。不能因为某个浮点转换修补已存在,就宣称所有大整数与slice助手也一起修好了。
切回RESP2会改变整个连接的协议行为,可能影响其他命令和Pub/Sub路径,不宜作为没有范围评估的全局修复。也不需要为本题开启服务器DEBUG命令:已知ZSCORE即可验证实际业务读取路径。
同时检查小数与缺失值
在隔离数据中覆盖整数形分数、小数、成员不存在及业务允许的边界值,分别确认两个协议下的业务结果一致。通用数组命令还需逐元素检查,不能只验证第一个值。
后续采用依赖修正时,应核对具体正式版本支持了哪些Go类型。最终验收是数值含义、精度与错误处理都保留,而不只是类型错误消失。


