2019年8月29日木曜日

redigo でネストな構造体を扱う方法

概要

前回 redigo の基本的な使い方を紹介しました
redis を使っていると複雑な構造を持つデータを格納したくなります
今回は redigo で階層的な構造体を扱う方法を紹介します 

環境

  • CentOS 7.6.1810
  • go 1.12.1
    • redigo d3876d43bbbeb98b4d67309b4d3eef49438ef74c

結論

ハッシュを使って ScanStruct で構造体にマッピングすることはできないようです
https://github.com/gomodule/redigo/issues/52

結論としては JSON 文字列を set し取り出すときは get でまず文字列として取り出しそれを構造体にマッピングします

以下サンプルコードです

サンプルコード

package main

import (
    "encoding/json"
    "fmt"
    "github.com/gomodule/redigo/redis"
    "math"
    "time"
)

type Profile struct {
    Name      string    `json:"name"`
    Age       int       `json:"age"`
    Address   Address   `json:"address"`
    Test      Test      `json:"test"`
    CreatedAt time.Time `json:"created_at"`
}

type Address struct {
    Zip  string `json:"zip"`
    City string `json:"city"`
}

type Test struct {
    I64 int64   `json:"i64"`
    F64 float64 `json:"f64"`
}

func main() {
    c, err := redis.Dial("tcp", "localhost:6379")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer c.Close()
    // nested struct
    p := Profile{
        Name: "hawksnowlog",
        Age:  99,
        Address: Address{
            Zip:  "123-4567",
            City: "123-4567",
        },
        Test: Test{
            I64: math.MaxInt64,
            F64: math.MaxFloat64,
        },
        CreatedAt: time.Now(),
    }
    // to json
    j, err := json.Marshal(p)
    if err != nil {
        fmt.Println(err)
        return
    }
    // debug print a json string
    fmt.Println(string(j))
    // set a json string
    _, err = c.Do("set", "profile", j)
    if err != nil {
        fmt.Println(err)
        return
    }

    // get a json string as bytes
    j2, err := redis.Bytes(c.Do("get", "profile"))
    if err != nil {
        fmt.Println(err)
        return
    }
    // bytes json to struct
    p2 := Profile{}
    err = json.Unmarshal(j2, &p2)
    if err != nil {
        fmt.Println(err)
        return
    }
    // debug print struct fields
    fmt.Println(p2.Name)
    fmt.Println(p2.Age)
    fmt.Println(p2.Address.Zip)
    fmt.Println(p2.Address.City)
    fmt.Println(p2.Test.I64)
    fmt.Println(p2.Test.F64)
    fmt.Println(p2.CreatedAt.Day())
}

json.Marshal は結構賢いようで time や int64, float64 もちゃんと構造体に合わせてキャストしてくれました

0 件のコメント:

コメントを投稿