在struct的字段上实现Redigo Scanner接口

时间:2017-10-24 12:51:02

标签: go redis redigo

我有一个看起来像这样的结构:

type authEnum int

const (
    never authEnum = iota
    sometimes
    always
)

type Attrs struct {
    Secret         string   `redis:"secret"`
    RequireSecret  authEnum `redis:"requireSecret"`
    UserID         string   `redis:"userId"`
}

func (e *authEnum) RedisScan(src interface{}) error {
    // This never gets called!
    if e == nil {
        return fmt.Errorf("nil pointer")
    }
    switch src := src.(type) {
    case string:
        if src == "false" || src == "never" {
            *e = never
        } else if src == "sometimes" {
            *e = sometimes
        } else { // "always" or "true"
            *e = always
        }
    default:
        return fmt.Errorf("cannot convert authEnum from %T to %T", src, e)
    }
    return nil
}

func getAttributes(ctx *AppContext, hash string) (*Attrs, error) {
    rc := ctx.RedisPool.Get()
    values, err := redis.Values(rc.Do("HGETALL", "redishash"))
    rc.Close()
    if err != nil {
        return nil, err
    }
    attrs := Attrs{}
    redis.ScanStruct(values, &attrs)
    return &attrs, nil
}

如何在RequireSecret属性上实施Scanner界面,以解析authEnum"never""sometimes"中的"always"类型redis哈希值?

如何计算值并将其分配给authEnum? 在我的代码示例中,RedisScan永远不会被调用。

2 个答案:

答案 0 :(得分:2)

您不是在字段上实现接口,而是在类型上实现。

您可以让authEnum类型满足界面,只需在该类型上创建一个签名为RedisScan(src interface{}) error的方法即可。

要分配给接收器,您需要接收指针。然后您可以这样分配:

func (e *authEnum) RedisScan(src interface{}) error {
    var value authEnum
    // Logic here to convert src to value
    *e = value
}

答案 1 :(得分:1)

在指针接收器上实现该方法。 Redis批量字符串表示为[]字节,而不是字符串:

func (e *authEnum) RedisScan(src interface{}) error {
    b, ok := src.([]byte)
    if !ok {
        return fmt.Errorf("cannot convert authEnum from %T to %T", src, b)
    }
    switch string(b) {
    case "false", "never":
        *e = never
    case "sometimes":
        *e = sometimes
    default:
        *e = always
    }
    return nil
}

始终检查并处理错误。从ScanStruct返回的错误报告了类型问题。

无需检查指向struct成员的nil指针。如果ScanStruct的参数为零,那么在调用RedisScan方法之前,Redigo会很恐慌。