2017-10-24 1 views
0

Ich habe eine Struktur, die wie folgt aussieht:Implementierung Redigo Scanner-Schnittstelle auf ein Feld der Struktur

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 
} 

Wie implementiere ich die Scanner Schnittstelle auf das RequireSecret Attribute einen authEnum Typen aus "never", "sometimes" oder "always" zu analysieren Redis Hashwerte?

Wie berechne ich den Wert und weise ihn dem authEnum zu? In meinem Codebeispiel wird nie RedisScan aufgerufen.

Antwort

1

Implementieren Sie die Methode auf einem Zeigerempfänger. Redis Bulk-Strings werden als [] Byte, nicht als String dargestellt:

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 
} 

Überprüfen Sie immer und behandeln Sie Fehler. Der von ScanStruct zurückgegebene Fehler meldet das Typproblem.

Es ist nicht notwendig, nach dem nil-Zeiger auf das Strukturelement zu suchen. Wenn das Argument für ScanStruct gleich Null ist, wird Redigo lange vor dem Aufruf der Rediscan-Methode in Panik geraten.

+0

Side Kommentar: Wenn Sie nicht brauchen, um Struktur Felder einzeln über die Redis-API zugreifen, dann ist es in der Regel besser zu kodieren Strukturen zu einem Redis Bulk-String mit Gob, Json, Yaml. –

+0

Danke für die saubere RedisScan-Funktion! Dies wird jedoch immer noch nicht von ScanStruct aufgerufen. –

+0

Das Programm unter https://play.golang.org/p/6fBVcGOupX funktioniert wie erwartet. Bestätigen Sie, dass die Antwort des Befehls das Feld enthält. –

2

Sie implementieren keine Schnittstellen für Felder, sondern für Typen.

Sie können Ihren authEnum Typ die Schnittstelle erfüllen, indem Sie einfach eine Methode mit der Signatur RedisScan(src interface{}) error für diesen Typ erstellen.

Um dem Empfänger zuzuweisen, müssen Sie einen Zeiger erhalten. Dann können Sie es wie folgt zuweisen:

+0

Aus irgendeinem Grund wird RedisScan nie angerufen, muss ich noch etwas tun, um es anzuschließen? –

+1

Es ist schwer ohne mehr Code zu sagen. Rufen Sie ScanStruct an? – bigless

+0

Möglicherweise müssen Sie Ihren Feldtyp in '* authEnum' (ein Zeiger) ändern. – Peter

Verwandte Themen