猿问

在 Go 中通过一个接口{}切片搜索接口{}的函数

我正在尝试实现一个函数,该函数接受任何类型的元素和相同类型的切片,并在第二个元素中搜索第一个元素,将其位置作为结果,否则为 -1。


我不是Go专家,所以我的第一个想法是将要搜索的元素作为interface{}传递,将切片作为[]interface{}传递,但它并没有真正起作用。


这是我尝试过的:


package main


import (

    "fmt"

)


func IsElementInListWithPos(element interface{}, list []interface{}) int {

    for i := range list {

        if list[i] == element {

            return i

        }

    }


    return -1

}


func main() {

    list1 := []int{1, 2, 3, 4, 5, 6}

    list2 := []string{"a", "b", "c", "d"}

    pos1 := IsElementInListWithPos(3, list1)

    pos2 := IsElementInListWithPos("a", list2)

    fmt.Println(pos1, pos2)

}


它给了我以下错误:


cannot use list (type []int) as type []interface {} in argument to IsElementInListWithPos

cannot use list2 (type []string) as type []interface {} in argument to IsElementInListWithPos

知道如何在不实际使用两个不同函数的情况下解决这个问题吗?提前致谢。


Cats萌萌
浏览 144回答 2
2回答

森栏

sort包演示了如何使用接口以与类型无关的方式实现算法。线性搜索需要两个基本操作,具体取决于 haystack 元素类型:Len 和 Equal。因此,我们可以编写以下 Haystack 接口和使用它的搜索函数:type Haystack interface {&nbsp; &nbsp; Len() int&nbsp; &nbsp; Equal(int, interface{}) bool}func Search(haystack Haystack, needle interface{}) int {&nbsp; &nbsp; for i := 0; i < haystack.Len(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; if haystack.Equal(i, needle) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1}这使得 Haystack 的编写实现变得简单,但不是类型安全的:type Strings []stringfunc (s Strings) Len() int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { return len(s) }func (s Strings) Equal(i int, x interface{}) bool { return s[i] == x.(string) }type Ints []intfunc (s Ints) Len() int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { return len(s) }func (s Ints) Equal(i int, x interface{}) bool { return s[i] == x.(int) }func main() {&nbsp; &nbsp; strings := []string{"b", "a", "c", "d"}&nbsp; &nbsp; fmt.Println(Search(Strings(strings), "c")) // 2&nbsp; &nbsp; fmt.Println(Search(Strings(strings), "e")) // -1&nbsp; &nbsp; ints := []int{2, 1, 3, 4}&nbsp; &nbsp; fmt.Println(Search(Ints(ints), 3)) // 2&nbsp; &nbsp; fmt.Println(Search(Ints(ints), 5)) // -1}请注意 Equal 方法中的类型断言。为了使这个类型安全,我们必须去掉interface{}Equal 的参数:type Haystack interface {&nbsp; &nbsp; Len() int&nbsp; &nbsp; Equal(int) bool}func Search(haystack Haystack) int {&nbsp; &nbsp; for i := 0; i < haystack.Len(); i++ {&nbsp; &nbsp; &nbsp; &nbsp; if haystack.Equal(i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1}type Strings struct {&nbsp; &nbsp; hs&nbsp; &nbsp; &nbsp;[]string&nbsp; &nbsp; needle string}func (s Strings) Len() int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return len(s.hs) }func (s Strings) Equal(i int) bool { return s.hs[i] == s.needle }type Ints struct {&nbsp; &nbsp; hs&nbsp; &nbsp; &nbsp;[]int&nbsp; &nbsp; needle int}func (s Ints) Len() int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return len(s.hs) }func (s Ints) Equal(i int) bool { return s.hs[i] == s.needle }func main() {&nbsp; &nbsp; strings := []string{"b", "a", "c", "d"}&nbsp; &nbsp; fmt.Println(Search(Strings{strings, "c"})) // 2&nbsp; &nbsp; fmt.Println(Search(Strings{strings, "e"})) // -1&nbsp; &nbsp; ints := []int{2, 1, 3, 4}&nbsp; &nbsp; fmt.Println(Search(Ints{ints, 3})) // 2&nbsp; &nbsp; fmt.Println(Search(Ints{ints, 5})) // -1}这使得界面实现和搜索功能的使用变得更加复杂。这个故事的寓意是,以这种方式使用接口需要足够复杂的算法才值得这样做。如果为特定类型编写接口实现比为算法编写具体实现需要更多工作,那么只需编写您需要的具体函数即可:func SearchStr(haystack []string, needle string) int {&nbsp; &nbsp; for i, x := range haystack {&nbsp; &nbsp; &nbsp; &nbsp; if x == needle {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1}func SearchInt(haystack []int, needle int) int {&nbsp; &nbsp; for i, x := range haystack {&nbsp; &nbsp; &nbsp; &nbsp; if x == needle {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1}func main() {&nbsp; &nbsp; strings := []string{"b", "a", "c", "d"}&nbsp; &nbsp; fmt.Println(SearchStr(strings, "c")) // 2&nbsp; &nbsp; fmt.Println(SearchStr(strings, "e")) // -1&nbsp; &nbsp; ints := []int{2, 1, 3, 4}&nbsp; &nbsp; fmt.Println(SearchInt(ints, 3)) // 2&nbsp; &nbsp; fmt.Println(SearchInt(ints, 5)) // -1}

守候你守候我

目前,不可能构建一个符合您所有标准的解决方案。一旦实现泛型,这将成为可能。或者您可以尝试使用 构建一个reflect,但这会产生一个复杂且可能缓慢的解决方案......所以我通常建议不要使用reflect像这样简单的东西(请参见下面的第二个片段)。你现在可以做的是使用类似的东西:func FindFirst(n int, f func(int) bool) int {&nbsp; &nbsp; for i := 0; i < n; i++ {&nbsp; &nbsp; &nbsp; &nbsp; if f(i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1}// in your code (s is the slice, e the value you are searching for)i := FindFirst(len(s), func(i int) bool {&nbsp; &nbsp; return s[i] == e})if i != -1 {&nbsp; &nbsp; // i is the index of the element with value e}正如你可以想象的那样,这没有多大意义......因为简单地显式地写出循环可以说更简单、更快、更惯用:// in your code (s is the slice, e the value you are searching for)for i, v := range s {&nbsp; &nbsp; if v == e {&nbsp; &nbsp; &nbsp; &nbsp; _ = i // i is the index of the element with value e&nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; }}显然,只有当切片中的元素数量很少时,整个方法(线性扫描)才合理。sort.Slice如果您的切片很大并且很少更改,那么(从时间复杂度的角度来看)首先对其进行排序 ( ),然后sort.Search对排序后的切片进行二分搜索 ( )可能更有意义。或者,您也可以使用 amap来代替: 在这种情况下(假设键很小)查找的时间复杂度为 O(1)。
随时随地看视频慕课网APP

相关分类

Go
我要回答