I'm using a third party Go lang library to query a LDAP database of users. The library returns a SearchResult slice of ResultUser that I need to map to my own User struct. The two structs have different field names and I only need specific fields from the ResultUser. Is there a more idiomatic way in Go to transform one struct to another.
I've created a demo below (link also on Go Playground). Thanks in advance for any advice you can give to this Go newbie!
package main
import "fmt"
type (
User struct {
id int32
firstName string
}
ResultUser struct {
uid int32
fname string
}
SearchResults []ResultUser
)
func main() {
results := getSearchResults()
users := mapResultsToUsers(results) // <-- This is the problem
fmt.Println("User struct:", users[0].id, users[0].firstName)
fmt.Println("User struct:", users[1].id, users[1].firstName)
}
// Simulates a query to a data with a library
func getSearchResults() (results SearchResults) {
return append(results, ResultUser{1, "John"}, ResultUser{2, "Jane"})
}
// Seems like a code smell to have to do this
// Is there a more idiomatic way to do this?
func mapResultsToUsers(results SearchResults) (users []User) {
for _, result := range results {
users = append(users, User{result.uid, result.fname})
}
return users
}
I've seen struct field tags but not sure if there is a better way.
I think that what you've got is pretty much the best solution, although I would move the mapping into a dedicated function, some like:
func fromResultUser(r *ResultUser) *User {
return &User{
id: r.uid,
firstName: r.fname,
}
}
Then mapResultsToUsers
becomes:
func mapResultsToUsers(results SearchResults) (users []*User) {
for _, result := range results {
users = append(users, fromResultUser(result))
}
return users
}
I've seen struct field tags but not sure if there is a better way.
You could put together something so that you could annotate your User
struct like:
User struct {
id int32 `mappedFrom:"uid"`
firstName string `mappedFrom:"fname"`
}
But the method required to implement that would be substantially more complex than the fromResultUser
presented here, and would involve becoming familiar with the reflect
package. I would argue that, as a colleague of mine is fond of saying, "the juice isn't worth the squeeze".