douchunjing6587 2019-09-19 10:04
浏览 7
已采纳

在Go中的界面{}上搜索界面{}的函数

I'm trying to implement a function that takes an element of any type and a slice of the same type and search the first inside the second, giving it's position as result or -1 otherwise.

I'm not a Go expert, so my first thought was to pass the element to search as interface{} and the slice as []interface{}, but it didn't really work.

Here's what I tried:

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)
}

It gives me the following errors:

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

Any idea how I could solve this issue without actually using two different functions? Thanks in advance.

  • 写回答

2条回答 默认 最新

  • dongsu3138 2019-09-19 14:33
    关注

    The sort package demonstrates how interfaces can be used to implement algorithms in a type-independent way.

    Linear search requires two essential operations that depend on the haystack element type, Len and Equal. So we can write the following Haystack interface and a Search function that using it:

    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
    }
    
    

    This makes writing implementations for Haystack simple, but not type-safe:

    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
    }
    
    

    Note the type assertions in the Equal methods. To make this type-safe we have to get rid of the interface{} argument to 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
    }
    

    This made both the interface implementations and using the Search function much more complicated.

    The moral of the story is that using interfaces this way requires a sufficiently complicated algorithm to be worth the trouble. If writing the interface implementation for a particular type is more work than writing the concrete implementation for the algorithm, well, then just write the concrete functions you need:

    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
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效