使用go-redis存储含嵌套结构体的Redis Hash的问题
问题:go-redis将嵌套结构体直接存入Redis Hash的实现
使用go-redis操作Redis时,嵌套的Bite结构体无法被自动存入目标Hash中。已知序列化整个结构体为JSON/YAML、创建关联子Hash这两种方案,但需求是将嵌套结构体的字段直接展开存入原Hash。
示例代码
package main import ( "context" "encoding/json" "strconv" "github.com/go-redis/redis/v8" ) type Bite struct { Power string `redis:"power"` Toxic bool `redis:"toxic"` } type Insect struct { Name string `redis:"name"` Description string `redis:"description"` Bite Bite Legs int `redis:"legs"` } // 实现redis.HashMarshaler接口,手动展开嵌套字段 func (i Insect) MarshalRedisHash() ([]string, error) { return []string{ "name", i.Name, "description", i.Description, "legs", strconv.Itoa(i.Legs), "bite.power", i.Bite.Power, "bite.toxic", strconv.FormatBool(i.Bite.Toxic), }, nil } func InitRedis() (*redis.Client, error) { return redis.NewClient(&redis.Options{ Addr: "localhost:6379", }), nil } func main() { MockSpidersResponse := []byte(`[ { "name": "blackwidow", "description": "small but deadly", "Bite": { "Power": "deadly", "toxic": true }, "legs": 8 }, { "name": "daddylonglegs", "description": "long and thin. harmless", "Bite": { "Power": "can't bite", "toxic": false }, "legs": 8 } ]`) var insects []Insect err := json.Unmarshal(MockSpidersResponse, &insects) if err != nil { panic(err) } client, err := InitRedis() if err != nil { panic(err) } defer client.Close() ctx := context.Background() for _, i := range insects { if err := client.HSet(ctx, "insect:"+i.Name, i).Err(); err != nil { panic(err) } } }
实现原理
go-redis的HSet方法默认仅处理结构体中的基本类型字段,无法自动识别并展开嵌套结构体。通过实现redis.HashMarshaler接口,我们可以手动控制Hash字段的生成逻辑:
- 将嵌套结构体
Bite的字段以bite.power、bite.toxic的命名形式展开到顶层Hash中 - 自定义字段命名规则,保持Hash结构的层级清晰性
效果验证
存入Redis后,目标Hash的结构会变为:
insect:blackwidow name: "blackwidow" description: "small but deadly" legs: "8" bite.power: "deadly" bite.toxic: "true"
内容的提问来源于stack exchange,提问作者rustyMagnet
相关产品推荐
相关产品推荐

