2015-12-07 3 views
3

J'ai récemment commencé à programmer avec Go sur Google App Engine et j'ai rencontré un blocage. Je viens de Java, donc ça a été un peu difficile de s'adapter à Go.Manipulation de tranches et d'interfaces

Je veux avoir une méthode qui me permette de passer un pointeur vers une tranche que je peux ensuite passer dans l'appel datastore.GetAll pour récupérer les résultats. Je veux ensuite parcourir les résultats et utiliser une assertion pour lancer une interface spécifique (Queryable) afin d'appeler une méthode Map().

Dans un premier temps, j'avais ce qui fonctionne correctement:

func (s ProjectService) RunQuery(context context.Context, q *datastore.Query, projects *[]Project) error { 
    keys, err := q.GetAll(context, projects) 
    if err != nil { 
     return err 
    } 

    for i, key := range keys { 
     (*projects)[i].Id = key.Encode() 
     (*projects)[i].CompanyId = (*projects)[i].Company.Encode() 
    } 
    return nil 
} 

Je veux avoir une méthode plus générique qui peut être appliquée à toute entité qui implémente une interface Queryable. L'idée est d'avoir un crochet qui me permet d'effectuer un post-traitement après avoir récupéré les résultats. J'ai regardé dans l'interface ProperyLoadSaver cependant je n'ai aucun accès à la clé réelle qui est associée à l'entité. Je voudrais stocker la représentation de chaîne du datastore.Key dans l'entité.

Ceci est l'interface Queryable:

type Queryable interface { 
    Map(*datastore.Key) error 
} 

est ici une entité exemple que je suis persistant au magasin GAE:

type Camera struct { 
    Id  string `datastore:"-"` 
    ProjectId string `datastore:"-"` 
    Name  string 
    Project *datastore.Key `json:"-"` 
    Active bool 
    Timestamp Timestamp 
} 

// Implement Queryable interface. Let me perform any additional mapping 
func (c *Camera) Map(key *datastore.Key) error { 
    c.Name = "Maybe do other things here" 
    c.Id = key.Encode() 
    return nil 
} 

L'idée est d'avoir quelque chose comme l'extrait ci-dessous.

func (c Crud) RunQuery(context context.Context, q *datastore.Query, entities interface{}) error { 
    keys, err := q.GetAll(context, entities)  
    v := reflect.ValueOf(entities) 
    dv := v.Elem() 

    for i, key := range keys {   
// I left this in to show that this worked however this won't let me enforce the interface contract 
//dv.Index(i).FieldByName("Id").Set(reflect.ValueOf(key.Encode())) 

     entity := dv.Index(i).Interface().(Queryable) 
     entity.Map(key)  
    } 

    return err 
} 

Toutefois, lorsque cette exécute, il affole ce qui suit:

PANIC: interface conversion: entity.Camera is not entity.Queryable: missing method Map goroutine 9 [running]:

Tout comme une note, je me rends compte de la manière appropriée d'effectuer une assertion est de faire si, comme, ok := elem.(Type); ok {} mais Je voulais juste voir quelle était l'erreur

Je devine que je reçois cette erreur parce que j'ai défini mon paramètre avec un récepteur de pointeur func (c *Camera) Map(key *datastore.Key) erroret non tfunc (c Camera) Map(key *datastore.Key) error Cependant, je veux modifier la valeur réelle.

Où est-ce que je me trompe? Est-ce que mon affichage Java-ness?

Étant que je suis très nouveau à Go, je peux être approcher complètement faux.

Répondre

1

Parce que la méthode est sur un récepteur de pointeur (comme il devrait être), utilisez le address de l'élément de tranche:

entity := dv.Index(i).Addr().Interface().(Queryable) 

Une autre approche consiste à utiliser une tranche de pointeurs pour le résultat:

var result []*Camera 
err := c.RunQuery(ctx, q, &result) 

Le code peut être écrit pour fonctionner avec [] Appareil photo ou [] * Appareil photo comme suit:

var queryableType = reflect.TypeOf((*Queryable)(nil)).Elem() 
needAddr := !dv.Type().Implements(queryableType) 

... 

var entity Queryable 
if needAddr { 
    entity = dv.Index(i).Addr().Interface().(Queryable) 
} else { 
    entity = dv.Index(i).Interface().(Queryable) 
} 
+0

'Addr()' m'a sorti de ce pétrin. Aussi, je ne savais pas que je pouvais utiliser [] * Camera vs * [] Camera. C'est quelque chose d'autre que je dois lire. –

+0

GetAll prend en charge les types d'argument résultat de * [] Camera et * [] * Camera.Dans les deux cas, GetAll alloue la tranche de résultat. Dans le second cas, GetAll alloue également les éléments. –