英文:
Go - Idiomatic way to map one struct to another
问题
我正在使用一个第三方的Go语言库来查询LDAP用户数据库。该库返回一个SearchResult切片,其中包含我需要映射到自己的User结构体的ResultUser。这两个结构体具有不同的字段名,而且我只需要ResultUser中的特定字段。在Go语言中,是否有更符合惯用方式的方法将一个结构体转换为另一个结构体呢?
我在下面创建了一个演示示例(链接也在Go Playground上)。非常感谢您对这个Go语言新手能给出的任何建议!
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) // <-- 这是问题所在
fmt.Println("User struct:", users[0].id, users[0].firstName)
fmt.Println("User struct:", users[1].id, users[1].firstName)
}
// 模拟使用库进行数据查询
func getSearchResults() (results SearchResults) {
return append(results, ResultUser{1, "John"}, ResultUser{2, "Jane"})
}
// 看起来这样做有点不太对劲
// 是否有更符合惯用方式的方法呢?
func mapResultsToUsers(results SearchResults) (users []User) {
for _, result := range results {
users = append(users, User{result.uid, result.fname})
}
return users
}
我见过结构体字段标签,但不确定是否有更好的方法。
英文:
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.
答案1
得分: 1
我认为你已经得到了相当不错的解决方案,尽管我会将映射移到一个专用函数中,类似于:
func fromResultUser(r *ResultUser) *User {
return &User{
id: r.uid,
firstName: r.fname,
}
}
然后mapResultsToUsers
变成:
func mapResultsToUsers(results SearchResults) (users []*User) {
for _, result := range results {
users = append(users, fromResultUser(result))
}
return users
}
我见过结构体字段标签,但不确定是否有更好的方法。
你可以组合一些东西,以便可以像这样注释你的User
结构体:
User struct {
id int32 `mappedFrom:"uid"`
firstName string `mappedFrom:"fname"`
}
但是,实现这种方法所需的方法比这里介绍的fromResultUser
要复杂得多,并且需要熟悉reflect
包。我会认为,正如我的一位同事喜欢说的那样,"得不偿失"。
英文:
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".
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论