假设我想编写一个在切片中查找值的函数
我直觉地想写:
func find(s []interface{}, f func(interface{})bool) int {
for i, item := range s {
if f(item) {
return i
}
}
return -1
}
Run Code Online (Sandbox Code Playgroud)
但是我无法用 Go 做到这一点。我可以有一个接口
Len() int
Value(int) interface{}
...
Run Code Online (Sandbox Code Playgroud)
这会起作用,但在我的实际代码中,事情更复杂(我需要做 slices[from:end] 等)、追加等,如果我在接口中重新定义所有这些,我最终会有很多代码. 有没有更好的办法?
您可以使用反射。我为一个项目写了这个函数,随意使用它:
// 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
}
Run Code Online (Sandbox Code Playgroud)
鉴于这里的所有答案都是在 go 添加泛型之前编写的,我将添加如何在 go1.18+ 中实现它
但请注意,从 go1.21 开始,有一个slices包包含许多有用的通用切片函数。
IndexFunc这是直接来自标准库的实现
// IndexFunc returns the first index i satisfying f(s[i]),
// or -1 if none do.
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
for i := range s {
if f(s[i]) {
return i
}
}
return -1
}
Run Code Online (Sandbox Code Playgroud)
请注意该函数如何使用类型参数[S ~[]E, E any]而不仅仅是S []any。差异在于 go 中切片的输入方式。就像您无法将一种类型的切片断言为另一种类型的切片一样,即使可以断言元素(例如,即使满足[]int{}.([]any),也是无效的),如果受到约束,则不能使用 an作为类型的参数到。intany[]intSS[]any
相反,它用于S ~[]E约束S为具有类型 元素的切片E,其中E可以是任何类型。此外,这允许函数单独使用元素类型,您可以通过第二个参数看到它:f func(E) bool。
| 归档时间: |
|
| 查看次数: |
2460 次 |
| 最近记录: |