dth2331 2017-05-10 13:09
浏览 68
已采纳

Golang和结构数组的结构

I have the following structs defined for movies and TV shows:

type Movie struct {
    ID      string `json:"id"`
    Viewers int    `json:"count"`
}
type TVShow struct {
    ID      string `json:"id"`
    Season  int    `json:"season"`
    Episode int    `json:"episode"`
    Viewers int    `json:"count"`
}

Then I have the following structs that contain several movies or TV shows by country:

type Movies struct {
    PenultimateMonth map[string][]Movie
    LastMonth        map[string][]Movie
}
type TVShows struct {
    PenultimateMonth map[string][]TVShow
    LastMonth        map[string][]TVShow
}

Finally, I have a data struct that holds everything:

type Data struct {
    Movies  Movies
    Seasons Seasons
}

What I need to do is collect all IDs of all movies and TV shows from penultimate and last month.

I figured out that I can use reflection for that, but I only managed to iterate over each Data element individually instead of all:

func GetIDs(data *Data, country string) []string {
    var ids []string

    movies := reflect.ValueOf(data.Movies).Elem()
    tvShows := reflect.ValueOf(data.TVShows).Elem()

    for i := 0; i < movies.NumField(); i++ {
        moviesSubset := movies.Field(i).Interface().(map[string][]Movie)
        for _, movie := range moviesSubset[country] {
            ids = append(ids, movie.ID)
        }
    }

    for i := 0; i < tvShows.NumField(); i++ {
        tvShowsSubset := tvShows.Field(i).Interface().(map[string][]TVShow)
        for _, tvShow := range tvShowsSubset[country] {
            ids = append(ids, tvShow.ID)
        }
    }

    return ids
}

Is it possible to simplify the GetIDs function so that I don't need the two separate blocks for movies and TV shows, but only one to collect all IDs?

  • 写回答

1条回答 默认 最新

  • douying4909 2017-05-10 13:47
    关注

    Use an interface:

    type identifiable interface {
        GetID() string
    }
    
    type identifiables interface {
        GetIDs() []string
    }
    

    Which you can implement like:

    func (m Movie) GetID() string { return m.ID }
    

    And use to collect IDs polymorphically.

    You could write it for each type, or make the maps store the interface and implement it once.

    type identifiable interface {
        GetID() string
    }
    
    type identifiables interface {
        GetIDs() []string
    }
    
    func (m Movie) GetID() string { return m.ID }
    
    type movies []Movie
    type moviesByCountry map[string]movies
    
    func (m movies) GetIDs() (ret []string) {
        for _, movie := range m {
            ret = append(ret, movie.GetID())
        }
        return
    }
    
    func (m moviesByCountry) GetIDs() (ret []string) {
        for _, slice := range m {
            ret = append(ret, slice.GetIDs()...)
        }
        return
    }
    
    func (d Data) GetCountryIDs(country string) []string {
        return gatherIDs(d.TVShows[country], d.Movies[country])
    }
    
    func gatherIDs(collections ...identifiables) (ret []string) {
        for _, collection := range collections {
            ret = append(ret, collection.GetIDs()...)
        }
        return
    }
    

    Here's a working playground example.

    Not very efficient but simple and consistent IMHO. If that's a problem it can be optimized by passing in an accumulator slice, but I would suggest an interface with a private method of you go that route.

    I think there's a reasonable case to be made for

    type identifiableByCountry interface {
        GetCountryIDs(string) []string
    }
    

    since both Data and the map(s) could implement that.

    If you prefer working with lambdas, you could also use something like:

    type collection interface {
        walk(func(identifiable))
    }
    

    and implement that on the collection types, using it as

    c.walk(func(o identifiable) {
        ids = append(ids, o.GetID())
    })
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)