2016-07-08 15 views
4

Ich habe zwei Funktionen in Go, die fast das gleiche tun. Sie nehmen eine Scheibe von Strukturen, die ein "ID" -Feld hat, und sortieren sie in eine Karte, die von diesem Feld indiziert wird. Sie hängen es dann an ein Feld einer anderen Struktur an, die ebenfalls durch die ID identifiziert wird.Zwei ähnliche Funktionen generisch

Die zwei Funktionen tun das gleiche, aber an zwei verschiedene Felder in der Struktur anhängen. Ich möchte die Methoden generisch machen, aber ich bin nicht sicher, wie es geht. Ich würde erwarten, dass es mit einem Zeiger gemacht werden könnte, aber ich bin mir nicht sicher, wie.

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

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

Wie es scheint, sie sehen ziemlich ähnlich. Ich bin in der Lage, es zu tun, außer ich kann nicht herausfinden, wie man das Feld "value.Id" in Zeile 11 generisch beschreibt.

Vielen Dank.

+5

Ich denke, für den Code, den Sie in Ihrer Frage vorgestellt haben, gibt es wenig Vorteile einer generischen Funktion. zwei getrennte Funktionen sind vollkommen in Ordnung, lesbar und typsicher. Sie können ein paar Zeilen Code speichern, indem Sie keine leere Scheibe für fehlende IDs erstellen (verwenden Sie stattdessen einfach nil). – kostya

+0

Ich habe versucht, eine Lösung zu erstellen, aber es scheint, dass Ihr Code fließt. Sie erstellen 'pds'- und' gds'-Maps, die von PremierDate und Genre 'Id' gekeyed werden, aber dann suchen Sie nach der Film-ID:' gs [value.Id] '. Macht für mich keinen Sinn. Beachten Sie auch anstelle von 'm [key] .Genres =' Sie können 'value.Genres =' –

Antwort

3

Während ich mit kostya darüber einig, dass es als separaten Funktionen, die völlig in Ordnung ist, könnte es weniger wartbar werden, wenn Sie mehr als 20 Einzelteile zu einem Film hinzufügen wollen - wie cast, revenues_per_country, etc. Sie mit 20 verlassen werden würden + Funktionen.

Die folgende Funktion würde es in eine Funktion komprimieren, aber Sie müssen für jedes Feld, das Sie hinzufügen möchten, verschiedene case Abschnitte hinzufügen.

es zu nutzen, legen Sie es einfach anstelle der aktuellen Anrufe:

Verbrauch: movies = addStuffToMovies(movies, genres)

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

Sie wahrscheinlich es dann eine interface durch Hinzufügen, einen Schritt weiter gehen könnte statt stuff interface{} Sie werden etwas wie []FieldInterface mit Anrufen wie GetID(), GetType() anstelle der verschiedenen case Abschnitte haben. Ich denke, du musst noch irgendwo einen Tipp machen, um es dem Film zuzuordnen. Dies wird wahrscheinlich zu viel Aufwand sein, wenn ein switch wie oben gut funktioniert.

Verwandte Themen