是否有一种惯用的方法来为golang切片做“in”

时间:2015-03-13 20:35:22

标签: go idiomatic

我想检查值是否在一片值中。实现这一目标的最佳方法是什么? 如下所示:

if "foo" in []string{"foo", "bar"}...

我已经编写了以下代码,但不确定它是如何惯用的(golang newbie):

// Convert a slice or array of a specific type to array of interface{}
func ToIntf(s interface{}) []interface{} {
    v := reflect.ValueOf(s)
    // There is no need to check, we want to panic if it's not slice or array
    intf := make([]interface{}, v.Len())
    for i := 0; i < v.Len(); i++ {
        intf[i] = v.Index(i).Interface()
    }
    return intf
}
func In(s []interface{}, val interface{}) bool {
    for _, v := range s {
        if v == val {
            return true
        }
    }
    return false
}

所以,使用它,这是我写的测试方法。

func TestIn(t *testing.T) {
    s := []string{"foo", "bar", "kuku", "kiki"}
    for _, v := range s {
        if !In(ToIntf(s), v) {
            t.Error("Should be in")
        }
    }
    if In(ToIntf(s), "foobar") {
        t.Error("Should not be in")
    }
}

2 个答案:

答案 0 :(得分:8)

用于通过简单循环表示的函数的惯用方法,以这种方式实现。例如,您的方法可以这样编写:

for _, value := range slice {
    if value == var {
        doSomething()
    }
}

显然,它有点冗长,但只有当你尝试翻译 language or choice here时才会这样。

进行反思的缺点是,如果你编写代码以集成到搜索中而不是简单地将其视为一个条件,那么就会使性能变得非常简单。

答案 1 :(得分:0)

如果你需要一种便宜的方法来检查这个(如果你必须经常检查),我会使用地图进行更便宜的查找。像这样:

type Foo string

var sl []string
var m map[string]int

//insert
sl = append(sl, "bar")
m["bar"] += 1

// delete ,e.g at position i
m[sl[i]] -= 1
sl[len(sl)-1], s[:len(sl)-1]


//test
if count := m["abc"]; count>0 {
 // "abc" in sl 
}

当然,如果您更改切片中的内容,两者都会增加开销。这取决于你的情况。

如果你的切片没有改变,你会做很多&#34; in&#34;测试你可以为它建立一个更容易的地图:

m := make(map[string]struct{}, len(sl))
for _, value := range sl {
    m[value] = struct{}
}

//test 

if _, ok := m["abc"]; ok {
  // "abc" is in sl
}