2015-12-26 4 views
2

Je tente de porter un C to Go.Recherche d'un élément par itérer dans une liste Aller

Je suis essentiellement à la recherche de quelque chose Aller semblable à find :: (a -> Bool) -> [a] -> Maybe a

Haskell je (à peu près) ce C pour trouver un élément dans une « liste » par itérer à travers elle:

struct foo { 
    struct foo *next; 
    char *name; 
} 

struct foo *foo_list; 

// Snip 

struct foo *foo = NULL; 
for (f = foo_list; f; f = f->next) { 
    if (!strcmp("bar", f->name) { 
     foo = f; 
    } 
} 

if (foo) 
    // Stuff 

Comment puis-je le faire gentiment et idiomatiquement dans Go?

La "liste" est susceptible d'être petite; les caractéristiques de performance ne sont pas particulièrement intéressantes. Je veux probablement un slice, ou un list? Une "liste" de Foo s ou *Foo s?

J'ai actuellement ce qui suit, mais je soupçonne que ce n'est pas particulièrement "idiomatique Go"!

var FooTable *list.List 

// Snip 

var foo *Foo = nil 

for e := FooTable.Front(); e != nil; e = e.Next() { 
    if e.Value.(*Foo).name == "bar" { 
     foo = e.Value.(*Foo) 
     break 
    } 
} 
+0

Quelles sont les caractéristiques de l'utilisation de la structure de données? Vous dites que sa petite taille et la performance n'est pas intéressante. Si elle est petite, quelle que soit la structure utilisée, elle ira probablement dans le cache, donc la simplicité et la robustesse dominent probablement. Cependant, quelles sont les opérations communes? La recherche domine-t-elle? Y a-t-il beaucoup d'insertions et de suppressions, même si elles restent petites? Les seules opérations délicates sur les tranches sont delete et insert, et elles sont encore assez simples à écrire dans Go. Si la seule valeur est une chaîne, alors une tranche de chaînes est probablement la plus simple. L'ajout de tri est facile aussi. – gbulmer

Répondre

6

Pour idiomatiques Go vous voulez une tranche de pointeurs vers Foo (mais si Foo est très petit, vous pouvez choisir juste une tranche de Foo), donc

var foos []*Foo 

Et puis pour la recherche

var found *Foo 
for _, foo := range foos { 
    if foo.name == "bar" { 
     found = foo 
     break 
    } 
} 

if found != nil { 
    // stuff 
} 

Si vous faites cela beaucoup vous l'envelopper avec certains types quelque chose comme ça

type Foos []*Foo 

func (fs Foos) find(what string) (foo *Foo) { 
    for _, foo = range foos { 
     if foo.name == what { 
      return foo 
     } 
    } 
    return nil 
} 

Ensuite, vous pouvez faire

var foos Foos 
foo := foos.find("bar") 
if foo != nil { 
    // something 
} 

PS Nice répondre à une question pour quelqu'un que je l'ai rencontré en fait!

+0

Haha c'est un petit internet! Merci beaucoup: D –

+2

S'il vous plaît noter que si l'élément recherché n'est pas dans la tranche, votre variable 'foo' tiendra le dernier élément de la tranche, certainement pas ce que vous voulez. – icza

+0

@icza oui vous avez raison! (J'ai suivi le code OP de trop près!) J'ai corrigé ça maintenant. –