为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
Cats萌萌 2023-07-26 13:43:11
我正在尝试实现一个函数,该函数接受任何类型的元素和相同类型的切片,并在第二个元素中搜索第一个元素,将其位置作为结果,否则为 -1。我不是Go专家,所以我的第一个想法是将要搜索的元素作为interface{}传递,将切片作为[]interface{}传递,但它并没有真正起作用。这是我尝试过的:package mainimport (    "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 IsElementInListWithPoscannot use list2 (type []string) as type []interface {} in argument to IsElementInListWithPos知道如何在不实际使用两个不同函数的情况下解决这个问题吗?提前致谢。
查看完整描述

2 回答

?
森栏

TA贡献1810条经验 获得超5个赞

sort包演示了如何使用接口以与类型无关的方式实现算法。


线性搜索需要两个基本操作,具体取决于 haystack 元素类型:Len 和 Equal。因此,我们可以编写以下 Haystack 接口和使用它的搜索函数:


type Haystack interface {

    Len() int

    Equal(int, interface{}) bool

}


func Search(haystack Haystack, needle interface{}) int {

    for i := 0; i < haystack.Len(); i++ {

        if haystack.Equal(i, needle) {

            return i

        }

    }

    return -1

}


这使得 Haystack 的编写实现变得简单,但不是类型安全的:


type Strings []string


func (s Strings) Len() int                        { return len(s) }

func (s Strings) Equal(i int, x interface{}) bool { return s[i] == x.(string) }


type Ints []int


func (s Ints) Len() int                        { return len(s) }

func (s Ints) Equal(i int, x interface{}) bool { return s[i] == x.(int) }


func main() {

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

    fmt.Println(Search(Strings(strings), "c")) // 2

    fmt.Println(Search(Strings(strings), "e")) // -1


    ints := []int{2, 1, 3, 4}

    fmt.Println(Search(Ints(ints), 3)) // 2

    fmt.Println(Search(Ints(ints), 5)) // -1

}


请注意 Equal 方法中的类型断言。为了使这个类型安全,我们必须去掉interface{}Equal 的参数:


type Haystack interface {

    Len() int

    Equal(int) bool

}


func Search(haystack Haystack) int {

    for i := 0; i < haystack.Len(); i++ {

        if haystack.Equal(i) {

            return i

        }

    }

    return -1

}


type Strings struct {

    hs     []string

    needle string

}


func (s Strings) Len() int         { return len(s.hs) }

func (s Strings) Equal(i int) bool { return s.hs[i] == s.needle }


type Ints struct {

    hs     []int

    needle int

}


func (s Ints) Len() int         { return len(s.hs) }

func (s Ints) Equal(i int) bool { return s.hs[i] == s.needle }


func main() {

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

    fmt.Println(Search(Strings{strings, "c"})) // 2

    fmt.Println(Search(Strings{strings, "e"})) // -1


    ints := []int{2, 1, 3, 4}

    fmt.Println(Search(Ints{ints, 3})) // 2

    fmt.Println(Search(Ints{ints, 5})) // -1

}

这使得界面实现和搜索功能的使用变得更加复杂。


这个故事的寓意是,以这种方式使用接口需要足够复杂的算法才值得这样做。如果为特定类型编写接口实现比为算法编写具体实现需要更多工作,那么只需编写您需要的具体函数即可:


func SearchStr(haystack []string, needle string) int {

    for i, x := range haystack {

        if x == needle {

            return i

        }

    }

    return -1

}


func SearchInt(haystack []int, needle int) int {

    for i, x := range haystack {

        if x == needle {

            return i

        }

    }

    return -1

}


func main() {

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

    fmt.Println(SearchStr(strings, "c")) // 2

    fmt.Println(SearchStr(strings, "e")) // -1


    ints := []int{2, 1, 3, 4}

    fmt.Println(SearchInt(ints, 3)) // 2

    fmt.Println(SearchInt(ints, 5)) // -1

}


查看完整回答
反对 回复 2023-07-26
?
守候你守候我

TA贡献1802条经验 获得超10个赞

目前,不可能构建一个符合您所有标准的解决方案。一旦实现泛型,这将成为可能。或者您可以尝试使用 构建一个reflect,但这会产生一个复杂且可能缓慢的解决方案......所以我通常建议不要使用reflect像这样简单的东西(请参见下面的第二个片段)。


你现在可以做的是使用类似的东西:


func FindFirst(n int, f func(int) bool) int {

    for i := 0; i < n; i++ {

        if f(i) {

            return i

        }

    }

    return -1

}


// in your code (s is the slice, e the value you are searching for)

i := FindFirst(len(s), func(i int) bool {

    return s[i] == e

})

if i != -1 {

    // 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 {

    if v == e {

        _ = i // i is the index of the element with value e

        break

    }

}

显然,只有当切片中的元素数量很少时,整个方法(线性扫描)才合理。sort.Slice如果您的切片很大并且很少更改,那么(从时间复杂度的角度来看)首先对其进行排序 ( ),然后sort.Search对排序后的切片进行二分搜索 ( )可能更有意义。或者,您也可以使用 amap来代替: 在这种情况下(假设键很小)查找的时间复杂度为 O(1)。


查看完整回答
反对 回复 2023-07-26
  • 2 回答
  • 0 关注
  • 131 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信