使两个相似的功能通用

时间:2016-07-08 08:36:49

标签: generics go slice generic-programming

我在Go中有两个功能几乎相同。它们采用一段具有“ID”字段的结构,并将其重新排序为由该字段索引的地图。然后,他们将它附加到另一个结构的字段,该结构也由ID标识。

这两个函数的作用相同,但附加到struct中的两个不同的字段。我想让方法通用,但我不知道该怎么做。我希望它可以使用指针完成,但我不确定如何。

功能1:

func addPremiereDatesToMovies(m []Movie, pd []PremiereDate) ([]Movie, error) {
    pds := make(map[int64][]PremiereDate)

    // Key-index the premiere-date array for easier lookup
    for _, value := range pd {
        pds[value.Id] = append(pds[value.Id], value)
    }

    // Append premiere dates to movies where such exist
    for key, value := range m {
        if _, ok := pds[value.Id]; !ok {  // <-- How to make this generic?
            m[key].PremiereDates = []PremiereDate{}
            continue
        }

        m[key].PremiereDates = pds[value.Id]
    }

    return m, nil
}

功能2:

func addGenresToMovies(m []Movie, g []Genre) ([]Movie, error) {
    gs := make(map[int64][]Genre)

    // Key-index the genre array for easier lookup
    for _, value := range g {
        gs[value.Id] = append(gs[value.Id], value)
    }

    // Append genres to movies where such exist
    for key, value := range m {
        if _, ok := gs[value.Id]; !ok { // <-- How to make this generic?
            m[key].Genres = []Genre{}
            continue
        }

        m[key].Genres = gs[value.Id]
    }

    return m, nil
}

看起来,它们看起来非常相似。我能够做到这一点,除了我无法弄清楚如何一般地描述第11行的“value.Id”字段。

谢谢。

1 个答案:

答案 0 :(得分:3)

虽然我同意kostya将其作为单独的功能完全正常,但如果您想要为电影添加20多个项目,可能会变得不那么易于维护 - 例如cast,{{1}你将留下20多个功能。

以下函数会将其压缩为一个函数,但您需要为要添加的每个字段添加不同的revenues_per_country部分。

要使用它,只需将其取下当前的电话:

使用方法: case

movies = addStuffToMovies(movies, genres)

您可以通过添加interface更进一步,然后通过// addStuffToMovies adds fields to a movie where the ID matches func addStuffToMovies(movies []Movie, stuff interface{}) []Movie { // Go through the movies list for current, movie := range movies { // check the type and append based on that switch v := stuff.(type) { // This is the section you'll need to duplicate for each type of field case []Genre: for _, item := range v { // if it matches, append it to Genres if item.Id == movie.Id { movies[current].Genres = append(movies[current].Genres, item) } } // This is the section you'll need to duplicate for each type of field case []PremiereDate: for _, item := range v { // if it matches, append it to PremiereDates if item.Id == movie.Id { movies[current].PremiereDates = append(movies[current].PremiereDates, item) } } } } return movies } ,{stuff interface{}之类的[]FieldInterface取代GetID()。 1}}而不是不同的GetType()部分。我认为你仍然需要在某处进行类型检查以实际将其分配给电影。当上面的case能够正常工作时,这可能会付出很多努力。