Implementing Redigo Scanner interface on a struct's field

偶尔善良 提交于 2019-12-13 07:37:16

问题


I have a struct that looks like this:

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
}

How do I implement the Scanner interface on the RequireSecret attribute to parse an authEnum type out of "never", "sometimes" or "always" redis hash values?

How do I calculate the value and assign it to the authEnum? In my code example RedisScan never gets called.


回答1:


Implement the method on a pointer receiver. Redis bulk strings are represented as []byte, not string:

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
}

Always check and handle errors. The error returned from ScanStruct reports the type problem.

There's no need to check for nil pointer to the struct member. If the argument to ScanStruct is nil, then Redigo will panic well before the RedisScan method is called.




回答2:


You don't implement interfaces on fields, but rather on types.

You can make your authEnum type satisfy the interface, simply by creating a method with the signature RedisScan(src interface{}) error on that type.

To assign to the receiver, you need to receive a pointer. Then you can assign to it as so:

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


来源:https://stackoverflow.com/questions/46911105/implementing-redigo-scanner-interface-on-a-structs-field

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!