问题
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