【问题标题】:Implementing Redigo Scanner interface on a struct's field在结构的字段上实现 Redigo Scanner 接口
【发布时间】:2017-10-24 12:51:01
【问题描述】:

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

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 接口以从"never""sometimes""always" redis 哈希值中解析出authEnum 类型?

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

【问题讨论】:

    标签: go redis redigo


    【解决方案1】:

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

    您可以使您的authEnum 类型满足接口,只需在该类型上创建一个带有签名RedisScan(src interface{}) error 的方法。

    要分配给接收者,你需要接收一个指针。然后你可以这样分配它:

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

    【讨论】:

    • 由于某种原因,RedisScan 永远不会被调用,我还需要做些什么来连接它吗?
    • 没有更多代码很难说。你打电话给 ScanStruct 吗?
    • 您可能需要将字段类型更改为*authEnum(指针)。
    • 我的代码看起来像这样,使用指针没有帮助gist.github.com/herkyl/18f52ade5cc08ed0a7fe2af1c688d2d2
    • 原来我的 redigo 已经过时了!更新后就可以了:)
    【解决方案2】:

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

    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返回的错误报告类型问题。

    无需检查指向结构成员的 nil 指针。如果 ScanStruct 的参数为 nil,那么 Redigo 将在调用 RedisScan 方法之前发生恐慌。

    【讨论】:

    • 旁注:如果您不需要通过 Redis API 单独访问结构字段,那么通常最好使用 gob、json、yaml 将结构编码为 Redis 批量字符串。
    • 感谢干净的 RedisScan 功能!然而,这仍然永远不会被 ScanStruct 调用
    • play.golang.org/p/6fBVcGOupX 的程序按预期工作。确认命令的响应包含该字段。
    • 原来我运行的是旧版本的 redigo,更新后就可以了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    相关资源
    最近更新 更多