使用redigo扫描Redis数据至指针结构体时遇类型转换错误求助
这个报错的核心原因是:Redigo的Scan函数无法直接将Redis返回的bulk string(或nil值)赋值给*string类型的指针。Redigo的默认扫描规则中,没有针对**string(因为你传的是&usr.Nickname,而usr.Nickname本身是*string)的转换逻辑,所以会抛出类型不匹配的错误。
当你用HMSET存入可能为nil的*string值时,Redis中对应的字段会被存储为bulk nil(当指针为nil时)或字符串(当指针指向有效值时)。而HMGET返回的结果列表中,不存在的字段或存为nil的字段会以nil的形式返回给客户端,这时候直接用Scan映射到*string指针就会出问题。
修正方案:使用redis.NullString中转
Redigo提供了redis.NullString类型,专门用来处理Redis中可能为nil的字符串值,它包含两个字段:
String string:存储实际的字符串值Valid bool:标记该值是否有效(即Redis中不是nil)
你可以先将HMGET的结果扫描到NullString变量中,再手动转换为*string类型:
// 先获取HMGET结果 values, err := redis.Values(Cache.Do("HMGET", "key", "nickname", "phone")) if err != nil { // 处理错误 } // 定义NullString变量接收扫描结果 var nick, phone redis.NullString _, err = redis.Scan(values, &nick, &phone) if err != nil { // 处理错误 } // 转换为User结构体的*string字段 var usr User if nick.Valid { usr.Nickname = &nick.String } else { usr.Nickname = nil } if phone.Valid { usr.Phone = &phone.String } else { usr.Phone = nil }
为什么不能直接扫描到*string?
Redigo的Scan函数设计上,对于目标类型为*T的情况,它期望将Redis的值转换为T类型后赋值给指针指向的内存。但当目标是**string时(即*string的指针),Redis的nil值无法直接映射为Go的nil指针——因为Scan无法区分“要将指针设为nil”和“要将指针指向的字符串设为空”这两种情况,所以需要NullString来明确标记值是否有效。
额外优化:封装转换逻辑
如果经常需要处理这种*string与NullString的转换,可以封装一个辅助函数来简化代码:
func nullStringToPtr(ns redis.NullString) *string { if ns.Valid { return &ns.String } return nil }
然后使用时就可以简化为:
usr.Nickname = nullStringToPtr(nick) usr.Phone = nullStringToPtr(phone)
内容的提问来源于stack exchange,提问作者Daniele

