英文:
Is there an idiomatic way to do "in" for golang slices
问题
我想检查一个值是否在值的切片中。实现这个的最佳方法是什么?
类似以下的方式:
if "foo" in []string{"foo", "bar"}...
我写了下面的代码,但不确定它是否符合惯用写法(我是 Go 语言的新手):
// 将特定类型的切片或数组转换为 interface{} 类型的数组
func ToIntf(s interface{}) []interface{} {
v := reflect.ValueOf(s)
// 不需要检查,如果它不是切片或数组,我们希望引发 panic
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("应该存在")
}
}
if In(ToIntf(s), "foobar") {
t.Error("不应该存在")
}
}
英文:
I would like to check if a value is in a slice of values. What is the best way to achieve this?
Something like the following:
if "foo" in []string{"foo", "bar"}...
I've written the following code but not sure how idiomatic it is (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
}
So, to use this, here is a test method I wrote.
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")
}
}
答案1
得分: 8
在Go语言中,对于可以用简单循环表达的函数,惯用的方式就是这样实现。例如,你的方法可以这样写:
for _, value := range slice {
if value == var {
doSomething()
}
}
显然,这种方式更冗长,但只有在你试图在Go中翻译 language or choice here
时才会如此。
使用反射的缺点是,性能会受到影响,而且并不比将代码编写为与搜索集成而不仅仅是将其视为条件更简单。
英文:
The idiomatic way, in go, for functions that can be expressed with a simple loop, to be implemented that way. Your method, for example, could be written that way:
for _, value := range slice {
if value == var {
doSomething()
}
}
Obviously, it is somewhat more verbose, but that only if you try to translate language or choice here
in go.
The downside of doing reflection is that you botch performances without being that simpler than if you write your code to integrate to the search rather than simply considering it a condition.
答案2
得分: 0
如果你需要一种廉价的方法来频繁检查这个(如果你需要经常检查它),我建议使用一个映射(map)来进行更便宜的查找,就像这样:
type Foo string
var sl []string
var m map[string]int
//插入
sl = append(sl, "bar")
m["bar"] += 1
//删除,例如在位置i
m[sl[i]] -= 1
sl[len(sl)-1], sl[:len(sl)-1]
//测试
if count := m["abc"]; count > 0 {
// "abc"在sl中
}
当然,如果你在切片中更改了某些内容,这两种方法都会增加开销。这取决于你的情况。
如果你的切片不会改变,并且你将进行大量的“in”测试,你可以构建一个更简单的映射(map)来实现:
m := make(map[string]struct{}, len(sl))
for _, value := range sl {
m[value] = struct{}{}
}
//测试
if _, ok := m["abc"]; ok {
// "abc"在sl中
}
英文:
if you need a cheap way to check this (if you have to check it often) i would use a map for cheaper lookups. like this:
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
}
Of course both will add overhead if you change something in the slice. That would depend on your case.
If your slice does not change, and you will do a lot of "in" testing you could build an easier map for that:
m := make(map[string]struct{}, len(sl))
for _, value := range sl {
m[value] = struct{}
}
//test
if _, ok := m["abc"]; ok {
// "abc" is in sl
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论