Go – Idiomatic way to map one struct to another

huangapple go评论164阅读模式
英文:

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 &quot;fmt&quot;

type (
	User struct {
		id        int32
		firstName string
	}

	ResultUser struct {
		uid   int32
		fname string
	}
	SearchResults []ResultUser
)

func main() {
	results := getSearchResults()
	users := mapResultsToUsers(results) // &lt;-- This is the problem
	fmt.Println(&quot;User struct:&quot;, users[0].id, users[0].firstName)
	fmt.Println(&quot;User struct:&quot;, users[1].id, users[1].firstName)
}

// Simulates a query to a data with a library
func getSearchResults() (results SearchResults) {
	return append(results, ResultUser{1, &quot;John&quot;}, ResultUser{2, &quot;Jane&quot;})
}

// 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 &amp;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:&quot;uid&quot;`
    firstName string    `mappedFrom:&quot;fname&quot;`
}

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".

huangapple
  • 本文由 发表于 2023年2月24日 09:46:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75551930.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定