2016-07-22 34 views
3

比方说,我想写的是在切片在Go中,如何使用切片创建通用函数?

我直觉想写找到一个值的函数:

func find(s []interface{}, f func(interface{})bool) int { 
    for i, item := range s { 
     if f(item) { 
      return i 
     } 
    } 
    return -1 
} 

但我不管理与去做到这一点。我能有

Len() int 
Value(int) interface{} 
... 

一个接口,它的工作,但在我真正的代码的事情比较复杂(我需要做切片[来源:结束]等),追加,...等等,如果我重新定义所有这一切都在一个界面中,我最终得到了很多代码。有没有更好的办法?

+1

答案将是泛型,但不去做泛型。所以有效地使用反射,编写* n * find_ [类型]函数或遍布各处的接口。到目前为止,这并不令人愉快。 – Jakumi

+0

什么是数组?它们是任意的价值,还是它们需要比较的具体类型? – 2016-07-22 19:27:16

+0

@squint数组是“标准”的。我有一个数组[] A和一个数组[] B(所有结构,而不是接口) – Thomas

回答

1

您可以使用反射。我写了这个功能的一个项目,随意使用它:

// InSlice returns true if value is in slice 
func InSlice(value, slice interface{}) bool { 
    switch reflect.TypeOf(slice).Kind() { 
    case reflect.Slice, reflect.Ptr: 
     values := reflect.Indirect(reflect.ValueOf(slice)) 
     if values.Len() == 0 { 
      return false 
     } 

     val := reflect.Indirect(reflect.ValueOf(value)) 

     if val.Kind() != values.Index(0).Kind() { 
      return false 
     } 

     for i := 0; i < values.Len(); i++ { 
      if reflect.DeepEqual(values.Index(i).Interface(), val.Interface()) { 
       return true 
      } 
     } 
    } 
    return false 
} 
1

,如果你有预定义的类型一样[]int[]string,不想转换为[]interface{}看到这方面的工作示例代码(不使用reflect):

package main 

import "fmt" 

func find(s []int, f func(int) bool) int { 
    for i, item := range s { 
     if f(item) { 
      return i 
     } 
    } 
    return -1 
} 
func findString(s []string, f func(string) bool) int { 
    for i, item := range s { 
     if f(item) { 
      return i 
     } 
    } 
    return -1 
} 

func main() { 
    s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 
    fmt.Println(find(s, func(a int) bool { return a == 5 })) //5 

    strs := []string{"A", "B", "C"} 
    fmt.Println(findString(strs, func(a string) bool { return a == "B" })) //1 
} 

,或者您可以使用reflect,像这样的工作示例代码:

package main 

import "fmt" 
import "reflect" 

func find(slice interface{}, f func(interface{}) bool) int { 
    switch reflect.TypeOf(slice).Kind() { 
    case reflect.Slice: 
     values := reflect.Indirect(reflect.ValueOf(slice)) 
     for i := 0; i < values.Len(); i++ { 
      if f(values.Index(i).Interface()) { 
       return i 
      } 
     } 
    } 
    return -1 
} 

func main() { 
    a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 
    fmt.Println(find(a, func(i interface{}) bool { return i == 5 })) //5 

    b := []string{"A", "B", "C"} 
    fmt.Println(find(b, func(i interface{}) bool { return i == "B" })) //1 
} 

输出:

5 
1 

我希望这有助于。

+0

谢谢,但我已经有2个数组:a:= A [] {}和b:= B [] {} 在这种情况下你建议的工作是什么? find(a,fa)和find(b,fb)不能被调用。 (我只想找一个函数来避免重复它) – Thomas

+0

谢谢,但现在这是上面的答案:)但感谢辛勤工作,我+1。如果你想你可以保留你的答案的最后一部分,这是最好的,使事情更readbale – Thomas

0

我想,如果你想拥有任意值的片,并使用排序find功能,并具有标准[] reslicing的可能性,也许最好的办法是与其他结构

type proxy struct { 
    val interface{} 
} 

封装你interface{}和使用

func find(s []proxy , f func(proxy)bool) int {} 

和甲肝e f函数处理interface{}比较/类型转换。

+0

谢谢,但这迫使我复制我的数组到[]代理。但也许值得我不得不看 – Thomas

+0

我不明白这个解决方案。为什么'[] proxy'优于'[] interface {}'? –

+0

@PaulHankin当你有[] inteface {}参数传入[] A时,Go不会编译。 – Thomas