通过遍历Go列表来查找项目

huangapple go评论89阅读模式
英文:

Finding an item by iterating through a Go list

问题

我正在尝试将一些C代码移植到Go语言。

我基本上在寻找Go中类似于Haskell的find :: (a -> Bool) -> [a] -> Maybe a的功能。

我有以下(大致)用于在“列表”中通过迭代查找项目的C代码:

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

struct foo *foo_list;

// 省略

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

if (foo)
    // 处理

在Go中,我应该如何以一种漂亮和习惯性的方式实现这个功能?

这个“列表”可能很小,性能特征并不特别重要。

我可能需要一个slice还是一个list?是Foo的“列表”还是*Foo的“列表”?

目前我有以下代码,但我怀疑它不是特别“习惯用法的Go”!

var FooTable *list.List

// 省略

var foo *Foo = nil

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

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
    }
}

答案1

得分: 6

对于习惯用法的Go语言,你需要一个指向Foo的指针切片(如果Foo非常小,你也可以选择只用Foo的切片),所以代码如下:

var foos []*Foo

然后进行搜索:

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

if found != nil {
    // 处理逻辑
}

如果你经常这样做,你可以将其封装成一些类型,类似这样:

type Foos []*Foo

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

然后你可以这样使用:

var foos Foos
foo := foos.find("bar")
if foo != nil {
    // 处理逻辑
}

PS 很高兴能回答一个我真正见过的人的问题!

英文:

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!

huangapple
  • 本文由 发表于 2015年12月26日 22:06:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/34472070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定