Kristian Glass
Kristian Glass

Reputation: 38510

Finding an item by iterating through a Go list

I'm attempting to port some C to Go.

I'm essentially looking for something in Go akin to Haskell's find :: (a -> Bool) -> [a] -> Maybe a

I have (roughly) this C for finding an item in a "list" by iterating through it:

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

How can I do this nicely and idiomatically in Go?

The "list" is likely to be small; performance characteristics aren't particularly interesting.

Am I likely to want a slice, or a list? A "list" of Foos or *Foos?

I currently have the following, but I suspect it's not particularly "idiomatic 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
    }
}

Upvotes: 2

Views: 105

Answers (1)

Nick Craig-Wood
Nick Craig-Wood

Reputation: 54079

For idiomatic Go you want a slice of pointers to Foo (though if Foo is very small you might choose just a slice of Foo), so

var foos []*Foo

And then for searching

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

if found != nil {
    // stuff
}

If you do this a lot you'll wrap it up with some types something like this

type Foos []*Foo

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

Then you can do

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

PS Nice to answer a question for someone I've actually met!

Upvotes: 6

Related Questions